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-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.0
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->generate(context->prngContext,
132  payload + payloadLen, 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_KEY_EXCH_FAILED)
414  {
415  //The key exchange has failed
417  "Key exchanged failed");
418  }
419  else if(error == ERROR_UNEXPECTED_MESSAGE)
420  {
421  //An inappropriate message has been received
423  "Unexpected packet");
424  }
425  else if(error == ERROR_INVALID_MESSAGE)
426  {
427  //A malformed message has been received
429  "Malformed packet");
430  }
431  else if(error == ERROR_INVALID_CHANNEL)
432  {
433  //Invalid channel number
435  "Invalid channel number");
436  }
437  else if(error == ERROR_FLOW_CONTROL)
438  {
439  //Flow control error
441  "Flow control error");
442  }
443  else if(error == ERROR_INVALID_GROUP)
444  {
445  //Diffie-Hellman group out of range
447  "Diffie-Hellman group out of range");
448  }
449  else
450  {
451  //Generic protocol error
453  "Protocol error");
454  }
455  }
456 
457  //The sequence number is incremented after every packet
458  sshIncSequenceNumber(connection->decryptionEngine.seqNum);
459 
460  //Return status code
461  return error;
462 }
463 
464 
465 /**
466  * @brief Encrypt an outgoing SSH packet
467  * @param[in] connection Pointer to the SSH connection
468  * @param[in,out] packet SSH packet to be encrypted
469  * @param[in,out] length Actual length of the SSH packet
470  * @return Error code
471  **/
472 
473 error_t sshEncryptPacket(SshConnection *connection, uint8_t *packet,
474  size_t *length)
475 {
476  error_t error;
477  size_t n;
478  uint8_t *data;
479  size_t dataLen;
480  SshEncryptionEngine *encryptionEngine;
481 
482  //Point to the encryption engine
483  encryptionEngine = &connection->encryptionEngine;
484 
485  //Get the actual length of the packet
486  n = *length;
487 
488  //Debug message
489  TRACE_VERBOSE("Packet to be encrypted (%" PRIuSIZE " bytes):\r\n", n);
490  TRACE_VERBOSE_ARRAY(" ", packet, n);
491 
492 #if (SSH_HMAC_SUPPORT == ENABLED)
493  //MAC-then-encrypt mode?
494  if(encryptionEngine->hashAlgo != NULL && !encryptionEngine->etm)
495  {
496  //The packet_length field and the payload will be encrypted
497  data = packet;
498  dataLen = n;
499 
500  //Compute message authentication code
501  sshAppendMessageAuthCode(encryptionEngine, packet, n);
502  }
503  else
504 #endif
505  {
506  //Point to the plaintext data to be encrypted
507  data = packet + sizeof(uint32_t);
508  dataLen = n - sizeof(uint32_t);
509  }
510 
511 #if (SSH_STREAM_CIPHER_SUPPORT == ENABLED)
512  //Stream cipher?
513  if(encryptionEngine->cipherMode == CIPHER_MODE_STREAM)
514  {
515  const CipherAlgo *cipherAlgo;
516 
517  //Cipher algorithm used to encrypt the packet
518  cipherAlgo = encryptionEngine->cipherAlgo;
519 
520  //Encrypt the contents of the SSH packet
521  cipherAlgo->encryptStream(&encryptionEngine->cipherContext, data,
522  data, dataLen);
523 
524  //Successful encryption
525  error = NO_ERROR;
526  }
527  else
528 #endif
529 #if (SSH_CBC_CIPHER_SUPPORT == ENABLED)
530  //CBC cipher mode?
531  if(encryptionEngine->cipherMode == CIPHER_MODE_CBC)
532  {
533  //Perform CBC encryption
534  error = cbcEncrypt(encryptionEngine->cipherAlgo,
535  &encryptionEngine->cipherContext, encryptionEngine->iv, data,
536  data, dataLen);
537  }
538  else
539 #endif
540 #if (SSH_CTR_CIPHER_SUPPORT == ENABLED)
541  //CTR cipher mode?
542  if(encryptionEngine->cipherMode == CIPHER_MODE_CTR)
543  {
544  uint_t m;
545 
546  //Retrieve cipher block size, in bits
547  m = encryptionEngine->cipherAlgo->blockSize * 8;
548 
549  //Perform CTR encryption
550  error = ctrEncrypt(encryptionEngine->cipherAlgo,
551  &encryptionEngine->cipherContext, m, encryptionEngine->iv, data,
552  data, dataLen);
553  }
554  else
555 #endif
556 #if (SSH_GCM_CIPHER_SUPPORT == ENABLED || SSH_RFC5647_SUPPORT == ENABLED)
557  //GCM AEAD cipher?
558  if(encryptionEngine->cipherMode == CIPHER_MODE_GCM)
559  {
560  //When using AES-GCM, the packet_length field is to be treated as
561  //additional authenticated data, not as plaintext (refer to RFC 5647,
562  //section 7.3)
563  error = gcmEncrypt(&encryptionEngine->gcmContext, encryptionEngine->iv,
564  12, packet, 4, data, data, dataLen, packet + n,
565  encryptionEngine->macSize);
566 
567  //The invocation counter is treated as a 64-bit integer and is
568  //incremented after each invocation of AES-GCM to process a binary
569  //packet (refer to RFC 5647, section 7.1)
570  sshIncInvocationCounter(encryptionEngine->iv);
571  }
572  else
573 #endif
574 #if (SSH_CHACHA20_POLY1305_SUPPORT == ENABLED)
575  //ChaCha20Poly1305 AEAD cipher?
576  if(encryptionEngine->cipherMode == CIPHER_MODE_CHACHA20_POLY1305)
577  {
578  ChachaContext chachaContext;
579  Poly1305Context poly1305Context;
580  uint8_t nonce[8];
581  uint8_t key[32];
582 
583  //The nonce consists of the packet sequence number encoded as a uint64
584  osMemset(nonce, 0, 4);
585  osMemcpy(nonce + 4, encryptionEngine->seqNum, 4);
586 
587  //The ChaCha20 instance keyed by K_1 is a stream cipher that is used
588  //only to encrypt the 4 byte packet length field
589  error = chachaInit(&chachaContext, 20, encryptionEngine->encKey + 32, 32,
590  nonce, 8);
591 
592  //Check status code
593  if(!error)
594  {
595  //The packet_length field is encrypted using a zero block counter to
596  //obtain the ciphertext length
597  chachaCipher(&chachaContext, packet, packet, 4);
598 
599  //The second ChaCha20 instance, keyed by K_2, is used in conjunction
600  //with Poly1305 to build an AEAD that is used to decrypt and
601  //authenticate the entire packet
602  error = chachaInit(&chachaContext, 20, encryptionEngine->encKey, 32,
603  nonce, sizeof(nonce));
604  }
605 
606  //Check status code
607  if(!error)
608  {
609  //Generate a Poly1305 key by taking the first 256 bits of ChaCha20
610  //stream output generated using K_2
611  chachaCipher(&chachaContext, NULL, key, 32);
612 
613  //The other 256 bits of the ChaCha20 block are discarded
614  chachaCipher(&chachaContext, NULL, NULL, 32);
615 
616  //Encrypt the packet payload
617  chachaCipher(&chachaContext, data, data, dataLen);
618 
619  //Initialize the Poly1305 function with the key calculated above
620  poly1305Init(&poly1305Context, key);
621 
622  //Compute MAC over the ciphertext of the packet length and the
623  //payload together
624  poly1305Update(&poly1305Context, packet, n);
625  poly1305Final(&poly1305Context, packet + n);
626 
627  //Debug message
628  TRACE_VERBOSE("Write sequence number:\r\n");
629  TRACE_VERBOSE_ARRAY(" ", &encryptionEngine->seqNum, 4);
630  TRACE_VERBOSE("Computed MAC:\r\n");
631  TRACE_VERBOSE_ARRAY(" ", packet + n, encryptionEngine->macSize);
632  }
633  }
634  else
635 #endif
636  //Invalid cipher mode?
637  {
638  //The specified cipher mode is not supported
640  }
641 
642 #if (SSH_HMAC_SUPPORT == ENABLED)
643  //Check status code
644  if(!error)
645  {
646  //Encrypt-then-MAC mode?
647  if(encryptionEngine->hashAlgo != NULL && encryptionEngine->etm)
648  {
649  //Compute message authentication code
650  sshAppendMessageAuthCode(encryptionEngine, packet, n);
651  }
652  }
653 #endif
654 
655  //Check status code
656  if(!error)
657  {
658  //The value resulting from the MAC algorithm must be transmitted without
659  //encryption as the last part of the packet
660  n += encryptionEngine->macSize;
661 
662  //Debug message
663  TRACE_VERBOSE("Encrypted packet (%" PRIuSIZE " bytes):\r\n", n);
664  TRACE_VERBOSE_ARRAY(" ", packet, n);
665 
666  //Return the length of the encrypted packet
667  *length = n;
668  }
669 
670  //Return status code
671  return error;
672 }
673 
674 
675 /**
676  * @brief Decrypt an incoming SSH packet
677  * @param[in] connection Pointer to the SSH connection
678  * @param[in,out] packet SSH packet to be decrypted
679  * @param[in,out] length Actual length of the SSH packet
680  * @return Error code
681  **/
682 
683 error_t sshDecryptPacket(SshConnection *connection, uint8_t *packet,
684  size_t *length)
685 {
686  error_t error;
687  size_t n;
688  size_t blockSize;
689  SshEncryptionEngine *decryptionEngine;
690 
691  //Initialize status code
692  error = NO_ERROR;
693 
694  //Point to the decryption engine
695  decryptionEngine = &connection->decryptionEngine;
696 
697  //Block cipher algorithm?
698  if(decryptionEngine->cipherMode == CIPHER_MODE_CBC ||
699  decryptionEngine->cipherMode == CIPHER_MODE_CTR)
700  {
701  //Encrypt-then-MAC mode?
702  if(decryptionEngine->etm)
703  {
704  //The packet_length field is not encrypted
705  blockSize = 4;
706  }
707  else
708  {
709  //Retrieve the cipher block size
710  blockSize = decryptionEngine->cipherAlgo->blockSize;
711  }
712  }
713  else
714  {
715  //The packet_length field is a 32-bit integer
716  blockSize = 4;
717  }
718 
719  //Get the actual length of the packet
720  n = *length;
721 
722  //Debug message
723  TRACE_VERBOSE("Packet to be decrypted (%" PRIuSIZE " bytes):\r\n", n);
724  TRACE_VERBOSE_ARRAY(" ", packet, n);
725 
726  //Check the length of the incoming packet
727  if(n >= (blockSize + decryptionEngine->macSize))
728  {
729  //The value resulting from the MAC algorithm is transmitted without
730  //encryption as the last part of the packet
731  n -= decryptionEngine->macSize;
732 
733 #if (SSH_HMAC_SUPPORT == ENABLED)
734  //Encrypt-then-MAC mode?
735  if(decryptionEngine->hashAlgo != NULL && decryptionEngine->etm)
736  {
737  //Verify message authentication code
738  error = sshVerifyMessageAuthCode(decryptionEngine, packet, n);
739  }
740 #endif
741 
742  //Check status code
743  if(!error)
744  {
745 #if (SSH_STREAM_CIPHER_SUPPORT == ENABLED)
746  //Stream cipher?
747  if(decryptionEngine->cipherMode == CIPHER_MODE_STREAM)
748  {
749  const CipherAlgo *cipherAlgo;
750 
751  //Cipher algorithm used to encrypt the packet
752  cipherAlgo = decryptionEngine->cipherAlgo;
753 
754  //Decrypt the contents of the SSH packet
755  cipherAlgo->decryptStream(&decryptionEngine->cipherContext,
756  packet + blockSize, packet + blockSize, n - blockSize);
757  }
758  else
759 #endif
760 #if (SSH_CBC_CIPHER_SUPPORT == ENABLED)
761  //CBC cipher mode?
762  if(decryptionEngine->cipherMode == CIPHER_MODE_CBC)
763  {
764  //Perform CBC decryption
765  error = cbcDecrypt(decryptionEngine->cipherAlgo,
766  &decryptionEngine->cipherContext, decryptionEngine->iv,
767  packet + blockSize, packet + blockSize, n - blockSize);
768  }
769  else
770 #endif
771 #if (SSH_CTR_CIPHER_SUPPORT == ENABLED)
772  //CTR cipher mode?
773  if(decryptionEngine->cipherMode == CIPHER_MODE_CTR)
774  {
775  uint_t m;
776 
777  //Retrieve cipher block size, in bits
778  m = decryptionEngine->cipherAlgo->blockSize * 8;
779 
780  //Perform CTR decryption
781  error = ctrDecrypt(decryptionEngine->cipherAlgo,
782  &decryptionEngine->cipherContext, m, decryptionEngine->iv,
783  packet + blockSize, packet + blockSize, n - blockSize);
784  }
785  else
786 #endif
787 #if (SSH_GCM_CIPHER_SUPPORT == ENABLED || SSH_RFC5647_SUPPORT == ENABLED)
788  //GCM AEAD cipher?
789  if(decryptionEngine->cipherMode == CIPHER_MODE_GCM)
790  {
791  //When using AES-GCM, the packet_length field is to be treated as
792  //additional authenticated data, not as plaintext (refer to
793  //RFC 5647, section 7.3)
794  error = gcmDecrypt(&decryptionEngine->gcmContext,
795  decryptionEngine->iv, 12, packet, blockSize, packet + blockSize,
796  packet + blockSize, n - blockSize, packet + n,
797  decryptionEngine->macSize);
798 
799  //The invocation counter is treated as a 64-bit integer and is
800  //incremented after each invocation of AES-GCM to process a binary
801  //packet (refer to RFC 5647, section 7.1)
802  sshIncInvocationCounter(decryptionEngine->iv);
803  }
804  else
805 #endif
806 #if (SSH_CHACHA20_POLY1305_SUPPORT == ENABLED)
807  //ChaCha20Poly1305 AEAD cipher?
808  if(decryptionEngine->cipherMode == CIPHER_MODE_CHACHA20_POLY1305)
809  {
810  size_t i;
811  uint8_t mask;
812  uint8_t nonce[8];
813  uint8_t key[32];
814  uint8_t mac[16];
815  ChachaContext chachaContext;
816  Poly1305Context poly1305Context;
817 
818  //The nonce consists of the packet sequence number encoded as a
819  //uint64
820  osMemset(nonce, 0, 4);
821  osMemcpy(nonce + 4, decryptionEngine->seqNum, 4);
822 
823  //The second ChaCha20 instance, keyed by K_2, is used in conjunction
824  //with Poly1305 to build an AEAD that is used to decrypt and
825  //authenticate the entire packet
826  error = chachaInit(&chachaContext, 20, decryptionEngine->encKey, 32,
827  nonce, sizeof(nonce));
828 
829  //Check status code
830  if(!error)
831  {
832  //Generate a Poly1305 key by taking the first 256 bits of ChaCha20
833  //stream output generated using K_2
834  chachaCipher(&chachaContext, NULL, key, 32);
835 
836  //The other 256 bits of the ChaCha20 block are discarded
837  chachaCipher(&chachaContext, NULL, NULL, 32);
838 
839  //Initialize the Poly1305 function with the key calculated above
840  poly1305Init(&poly1305Context, key);
841 
842  //Compute MAC over the ciphertext of the packet length and the
843  //payload together
844  poly1305Update(&poly1305Context, decryptionEngine->aad, blockSize);
845  poly1305Update(&poly1305Context, packet + blockSize, n - blockSize);
846  poly1305Final(&poly1305Context, mac);
847 
848  //Decrypt the packet payload
849  chachaCipher(&chachaContext, packet + blockSize, packet + blockSize,
850  n - blockSize);
851 
852  //The calculated MAC is then compared in constant time with the
853  //one appended to the packet
854  for(mask = 0, i = 0; i < 16; i++)
855  {
856  mask |= mac[i] ^ packet[n + i];
857  }
858 
859  //The message is authenticated if and only if the tags match
860  error = (mask == 0) ? NO_ERROR : ERROR_FAILURE;
861  }
862  }
863  else
864 #endif
865  //Invalid cipher mode?
866  {
867  //The specified cipher mode is not supported
869  }
870  }
871  }
872  else
873  {
874  //The packet is malformed
875  error = ERROR_INVALID_PACKET;
876  }
877 
878  //Check status code
879  if(!error)
880  {
881  //Debug message
882  TRACE_VERBOSE("Decrypted packet (%" PRIuSIZE " bytes):\r\n", n);
883  TRACE_VERBOSE_ARRAY(" ", packet, n);
884 
885 #if (SSH_HMAC_SUPPORT == ENABLED)
886  //MAC-then-encrypt mode?
887  if(decryptionEngine->hashAlgo != NULL && !decryptionEngine->etm)
888  {
889  //Verify message authentication code
890  error = sshVerifyMessageAuthCode(decryptionEngine, packet, n);
891  }
892 #endif
893  }
894 
895  //Check status code
896  if(!error)
897  {
898  //Return the length of the decrypted packet
899  *length = n;
900  }
901  else
902  {
903  //Failed to decrypt SSH packet
904  error = ERROR_DECRYPTION_FAILED;
905  }
906 
907  //Return status code
908  return error;
909 }
910 
911 
912 /**
913  * @brief Retrieve the length of an incoming SSH packet
914  * @param[in] connection Pointer to the SSH connection
915  * @param[in] packet Pointer to the received SSH packet
916  * @return Error code
917  **/
918 
919 error_t sshParsePacketLength(SshConnection *connection, uint8_t *packet)
920 {
921  error_t error;
922  size_t packetLen;
923 
924  //Initialize status code
925  error = NO_ERROR;
926 
927  //Convert the packet length to host byte order
928  packetLen = LOAD32BE(packet);
929  //The length of the packet does not include the packet_length field itself
930  packetLen += sizeof(uint32_t);
931 
932  //Sanity check
933  if(packetLen <= SSH_BUFFER_SIZE && packetLen > LOAD32BE(packet))
934  {
935  //Save the total length of the packet
936  connection->rxBufferLen = packetLen;
937  }
938  else
939  {
940  //Report an error
941  error = ERROR_INVALID_LENGTH;
942  }
943 
944  //Return status code
945  return error;
946 }
947 
948 
949 /**
950  * @brief Decrypt the length field of an incoming SSH packet
951  * @param[in] connection Pointer to the SSH connection
952  * @param[in,out] packet Pointer to the first block of data
953  * @return Error code
954  **/
955 
956 error_t sshDecryptPacketLength(SshConnection *connection, uint8_t *packet)
957 {
958  error_t error;
959 #if (SSH_HMAC_SUPPORT == ENABLED || SSH_CHACHA20_POLY1305_SUPPORT == ENABLED)
960  size_t blockSize;
961 #endif
962  size_t packetLen;
963  SshEncryptionEngine *decryptionEngine;
964 
965  //Initialize status code
966  error = NO_ERROR;
967 
968  //Point to the decryption engine
969  decryptionEngine = &connection->decryptionEngine;
970 
971 #if (SSH_HMAC_SUPPORT == ENABLED || SSH_CHACHA20_POLY1305_SUPPORT == ENABLED)
972  //Block cipher algorithm?
973  if(decryptionEngine->cipherMode == CIPHER_MODE_CBC ||
974  decryptionEngine->cipherMode == CIPHER_MODE_CTR)
975  {
976  //Encrypt-then-MAC mode?
977  if(decryptionEngine->etm)
978  {
979  //The packet_length field is not encrypted
980  blockSize = 4;
981  }
982  else
983  {
984  //Retrieve the cipher block size
985  blockSize = decryptionEngine->cipherAlgo->blockSize;
986  }
987  }
988  else
989  {
990  //The packet_length field is a 32-bit integer
991  blockSize = 4;
992  }
993 
994  //Debug message
995  TRACE_VERBOSE("Block to be decrypted (%" PRIuSIZE " bytes):\r\n", blockSize);
996  TRACE_VERBOSE_ARRAY(" ", packet, blockSize);
997 #endif
998 
999 #if (SSH_STREAM_CIPHER_SUPPORT == ENABLED)
1000  //Stream cipher?
1001  if(decryptionEngine->cipherMode == CIPHER_MODE_STREAM)
1002  {
1003  //MAC-then-encrypt mode?
1004  if(!decryptionEngine->etm)
1005  {
1006  const CipherAlgo *cipherAlgo;
1007 
1008  //Cipher algorithm used to encrypt the packet
1009  cipherAlgo = decryptionEngine->cipherAlgo;
1010 
1011  //Decrypt packet_length field
1012  cipherAlgo->decryptStream(&decryptionEngine->cipherContext, packet,
1013  packet, blockSize);
1014  }
1015  }
1016  else
1017 #endif
1018 #if (SSH_CBC_CIPHER_SUPPORT == ENABLED)
1019  //CBC cipher mode?
1020  if(decryptionEngine->cipherMode == CIPHER_MODE_CBC)
1021  {
1022  //MAC-then-encrypt mode?
1023  if(!decryptionEngine->etm)
1024  {
1025  //Perform CBC decryption
1026  error = cbcDecrypt(decryptionEngine->cipherAlgo,
1027  &decryptionEngine->cipherContext, decryptionEngine->iv, packet,
1028  packet, blockSize);
1029  }
1030  }
1031  else
1032 #endif
1033 #if (SSH_CTR_CIPHER_SUPPORT == ENABLED)
1034  //CTR cipher mode?
1035  if(decryptionEngine->cipherMode == CIPHER_MODE_CTR)
1036  {
1037  //MAC-then-encrypt mode?
1038  if(!decryptionEngine->etm)
1039  {
1040  uint_t m;
1041 
1042  //Retrieve cipher block size, in bits
1043  m = decryptionEngine->cipherAlgo->blockSize * 8;
1044 
1045  //Perform CTR decryption
1046  error = ctrDecrypt(decryptionEngine->cipherAlgo,
1047  &decryptionEngine->cipherContext, m, decryptionEngine->iv,
1048  packet, packet, blockSize);
1049  }
1050  }
1051  else
1052 #endif
1053 #if (SSH_GCM_CIPHER_SUPPORT == ENABLED || SSH_RFC5647_SUPPORT == ENABLED)
1054  //GCM AEAD cipher?
1055  if(decryptionEngine->cipherMode == CIPHER_MODE_GCM)
1056  {
1057  //The packet_length field is not encrypted
1058  }
1059  else
1060 #endif
1061 #if (SSH_CHACHA20_POLY1305_SUPPORT == ENABLED)
1062  //ChaCha20Poly1305 AEAD cipher?
1063  if(decryptionEngine->cipherMode == CIPHER_MODE_CHACHA20_POLY1305)
1064  {
1065  ChachaContext chachaContext;
1066  uint8_t nonce[8];
1067 
1068  //The nonce consists of the packet sequence number encoded as a uint64
1069  osMemset(nonce, 0, 4);
1070  osMemcpy(nonce + 4, decryptionEngine->seqNum, 4);
1071 
1072  //Initialize ChaCha20 context
1073  error = chachaInit(&chachaContext, 20, decryptionEngine->encKey + 32, 32,
1074  nonce, 8);
1075 
1076  //Check status code
1077  if(!error)
1078  {
1079  //Save the ciphertext of the packet length
1080  osMemcpy(decryptionEngine->aad, packet, blockSize);
1081 
1082  //The packet_length field is decrypted using a zero block counter to
1083  //obtain the plaintext length
1084  chachaCipher(&chachaContext, packet, packet, blockSize);
1085  }
1086  }
1087  else
1088 #endif
1089  //Invalid cipher mode?
1090  {
1091  //The specified cipher mode is not supported
1093  }
1094 
1095  //Check status code
1096  if(!error)
1097  {
1098  //Debug message
1099  TRACE_VERBOSE("Decrypted block (%" PRIuSIZE " bytes):\r\n", blockSize);
1100  TRACE_VERBOSE_ARRAY(" ", packet, blockSize);
1101 
1102  //Convert the packet length to host byte order
1103  packetLen = LOAD32BE(packet);
1104 
1105  //The length of the packet does not include the mac field and the
1106  //packet_length field itself
1107  packetLen += decryptionEngine->macSize + sizeof(uint32_t);
1108 
1109  //Sanity check
1110  if(packetLen <= SSH_BUFFER_SIZE && packetLen > LOAD32BE(packet))
1111  {
1112  //Save the total length of the packet
1113  connection->rxBufferLen = packetLen;
1114  }
1115  else
1116  {
1117  //Report an error
1118  error = ERROR_DECRYPTION_FAILED;
1119  }
1120  }
1121 
1122  //Return status code
1123  return error;
1124 }
1125 
1126 
1127 /**
1128  * @brief Parse SSH message
1129  * @param[in] connection Pointer to the SSH connection
1130  * @param[in] message Pointer to received message
1131  * @param[in] length Length of the message, in bytes
1132  * @return Error code
1133  **/
1134 
1135 error_t sshParseMessage(SshConnection *connection, const uint8_t *message,
1136  size_t length)
1137 {
1138  error_t error;
1139  uint8_t type;
1140 
1141  //Check the length of the message
1142  if(length >= sizeof(uint8_t))
1143  {
1144  //The first byte of the payload indicates the message type
1145  type = message[0];
1146 
1147  //Check message type
1148  if(type == SSH_MSG_KEXINIT)
1149  {
1150  //Key exchange begins with an SSH_MSG_KEXINIT message
1151  error = sshParseKexInit(connection, message, length);
1152  }
1153  else if(type >= SSH_MSG_KEX_MIN && type <= SSH_MSG_KEX_MAX)
1154  {
1155  //Parse key exchange method-specific messages
1156  error = sshParseKexMessage(connection, type, message, length);
1157  }
1158  else if(type == SSH_MSG_NEWKEYS)
1159  {
1160  //Key exchange ends with an SSH_MSG_NEWKEYS message
1161  error = sshParseNewKeys(connection, message, length);
1162  }
1163  else if(type == SSH_MSG_SERVICE_REQUEST)
1164  {
1165  //After the key exchange, the client requests a service using a
1166  //SSH_MSG_SERVICE_REQUEST message
1167  error = sshParseServiceRequest(connection, message, length);
1168  }
1169  else if(type == SSH_MSG_SERVICE_ACCEPT)
1170  {
1171  //If the server supports the service (and permits the client to use
1172  //it), it must respond with an SSH_MSG_SERVICE_ACCEPT message
1173  error = sshParseServiceAccept(connection, message, length);
1174  }
1175  else if(type == SSH_MSG_USERAUTH_REQUEST)
1176  {
1177  //All authentication requests use an SSH_MSG_USERAUTH_REQUEST message
1178  error = sshParseUserAuthRequest(connection, message, length);
1179  }
1180  else if(type == SSH_MSG_USERAUTH_SUCCESS)
1181  {
1182  //When the server accepts authentication, it must respond with a
1183  //SSH_MSG_USERAUTH_SUCCESS message
1184  error = sshParseUserAuthSuccess(connection, message, length);
1185  }
1186  else if(type == SSH_MSG_USERAUTH_FAILURE)
1187  {
1188  //If the server rejects the authentication request, it must respond
1189  //with an SSH_MSG_USERAUTH_FAILURE message
1190  error = sshParseUserAuthFailure(connection, message, length);
1191  }
1192  else if(type == SSH_MSG_USERAUTH_BANNER)
1193  {
1194  //The SSH server may send an SSH_MSG_USERAUTH_BANNER message at any
1195  //time after this authentication protocol starts and before
1196  //authentication is successful
1197  error = sshParseUserAuthBanner(connection, message, length);
1198  }
1200  {
1201  //Parse authentication method-specific messages
1202  error = sshParseUserAuthMessage(connection, type, message, length);
1203  }
1204  else if(type == SSH_MSG_GLOBAL_REQUEST)
1205  {
1206  //Both the client and server may send global requests at any time
1207  //(refer to RFC 4254, section 4)
1208  error = sshParseGlobalRequest(connection, message, length);
1209  }
1210  else if(type == SSH_MSG_REQUEST_SUCCESS)
1211  {
1212  //The recipient responds with either SSH_MSG_REQUEST_SUCCESS or
1213  //SSH_MSG_REQUEST_FAILURE
1214  error = sshParseRequestSuccess(connection, message, length);
1215  }
1216  else if(type == SSH_MSG_REQUEST_FAILURE)
1217  {
1218  //The recipient responds with either SSH_MSG_REQUEST_SUCCESS or
1219  //SSH_MSG_REQUEST_FAILURE
1220  error = sshParseRequestFailure(connection, message, length);
1221  }
1222  else if(type == SSH_MSG_CHANNEL_OPEN)
1223  {
1224  //When either side wishes to open a new channel, it then sends a
1225  //SSH_MSG_CHANNEL_OPEN message to the other side
1226  error = sshParseChannelOpen(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 = sshParseChannelOpenConfirmation(connection, message, length);
1233  }
1235  {
1236  //The recipient responds with either SSH_MSG_CHANNEL_OPEN_CONFIRMATION
1237  //or SSH_MSG_CHANNEL_OPEN_FAILURE
1238  error = sshParseChannelOpenFailure(connection, message, length);
1239  }
1240  else if(type == SSH_MSG_CHANNEL_REQUEST)
1241  {
1242  //All channel-specific requests use an SSH_MSG_CHANNEL_REQUEST message
1243  error = sshParseChannelRequest(connection, message, length);
1244  }
1245  else if(type == SSH_MSG_CHANNEL_SUCCESS)
1246  {
1247  //The recipient responds with either SSH_MSG_CHANNEL_SUCCESS or
1248  //SSH_MSG_CHANNEL_FAILURE
1249  error = sshParseChannelSuccess(connection, message, length);
1250  }
1251  else if(type == SSH_MSG_CHANNEL_FAILURE)
1252  {
1253  //The recipient responds with either SSH_MSG_CHANNEL_SUCCESS or
1254  //SSH_MSG_CHANNEL_FAILURE
1255  error = sshParseChannelFailure(connection, message, length);
1256  }
1258  {
1259  //Both parties use the SSH_MSG_CHANNEL_WINDOW_ADJUST message to adjust
1260  //the window
1261  error = sshParseChannelWindowAdjust(connection, message, length);
1262  }
1263  else if(type == SSH_MSG_CHANNEL_DATA)
1264  {
1265  //Data transfer is done with SSH_MSG_CHANNEL_DATA message
1266  error = sshParseChannelData(connection, message, length);
1267  }
1269  {
1270  //Extended data can be passed with SSH_MSG_CHANNEL_EXTENDED_DATA
1271  //messages
1272  error = sshParseChannelExtendedData(connection, message, length);
1273  }
1274  else if(type == SSH_MSG_CHANNEL_EOF)
1275  {
1276  //When a party will no longer send more data to a channel, it should
1277  //send an SSH_MSG_CHANNEL_EOF message
1278  error = sshParseChannelEof(connection, message, length);
1279  }
1280  else if(type == SSH_MSG_CHANNEL_CLOSE)
1281  {
1282  //When either party wishes to terminate the channel, it sends an
1283  //SSH_MSG_CHANNEL_CLOSE message
1284  error = sshParseChannelClose(connection, message, length);
1285  }
1286  else if(type == SSH_MSG_IGNORE)
1287  {
1288  //The SSH_MSG_IGNORE message can be used as an additional protection
1289  //measure against advanced traffic analysis techniques
1290  error = sshParseIgnore(connection, message, length);
1291  }
1292  else if(type == SSH_MSG_DEBUG)
1293  {
1294  //The SSH_MSG_DEBUG message is used to transmit information that may
1295  //help debugging
1296  error = sshParseDebug(connection, message, length);
1297  }
1298  else if(type == SSH_MSG_DISCONNECT)
1299  {
1300  //The SSH_MSG_DISCONNECT message causes immediate termination of the
1301  //connection. All implementations must be able to process this message
1302  error = sshParseDisconnect(connection, message, length);
1303  }
1304  else if(type == SSH_MSG_UNIMPLEMENTED)
1305  {
1306  //An implementation must respond to all unrecognized messages with an
1307  //SSH_MSG_UNIMPLEMENTED message in the order in which the messages
1308  //were received
1309  error = sshParseUnimplemented(connection, message, length);
1310  }
1311 #if (SSH_EXT_INFO_SUPPORT == ENABLED)
1312  else if(type == SSH_MSG_EXT_INFO)
1313  {
1314  //If a client or server offers "ext-info-c" or "ext-info-s"
1315  //respectively, it must be prepared to accept an SSH_MSG_EXT_INFO
1316  //message from the peer (refer to RFC 8308, section 2.2)
1317  error = sshParseExtInfo(connection, message, length);
1318  }
1319 #endif
1320  else
1321  {
1322  //Unrecognized message received
1323  error = sshParseUnrecognized(connection, message, length);
1324  }
1325  }
1326  else
1327  {
1328  //Malformed message
1329  error = ERROR_INVALID_MESSAGE;
1330  }
1331 
1332  //Return status code
1333  return error;
1334 }
1335 
1336 
1337 /**
1338  * @brief Compute message authentication code
1339  * @param[in] encryptionEngine Pointer to the encryption engine
1340  * @param[in] packet Pointer to the packet to be authenticated
1341  * @param[in] length of the packet, in bytes
1342  **/
1343 
1345  uint8_t *packet, size_t length)
1346 {
1347 #if (SSH_HMAC_SUPPORT == ENABLED)
1348  //Initialize HMAC calculation
1349  hmacInit(encryptionEngine->hmacContext, encryptionEngine->hashAlgo,
1350  encryptionEngine->macKey, encryptionEngine->hashAlgo->digestSize);
1351 
1352  //Compute MAC(key, sequence_number || unencrypted_packet)
1353  hmacUpdate(encryptionEngine->hmacContext, encryptionEngine->seqNum, 4);
1354  hmacUpdate(encryptionEngine->hmacContext, packet, length);
1355  hmacFinal(encryptionEngine->hmacContext, packet + length);
1356 
1357  //Debug message
1358  TRACE_VERBOSE("Write sequence number:\r\n");
1359  TRACE_VERBOSE_ARRAY(" ", &encryptionEngine->seqNum, 4);
1360  TRACE_VERBOSE("Computed MAC:\r\n");
1361  TRACE_VERBOSE_ARRAY(" ", packet + length, encryptionEngine->macSize);
1362 #endif
1363 }
1364 
1365 
1366 /**
1367  * @brief Verify message authentication code
1368  * @param[in] decryptionEngine Pointer to the decryption engine
1369  * @param[in] packet Pointer to the packet to be authenticated
1370  * @param[in] length of the packet, in bytes
1371  * @return Error code
1372  **/
1373 
1375  const uint8_t *packet, size_t length)
1376 {
1377 #if (SSH_HMAC_SUPPORT == ENABLED)
1378  size_t i;
1379  uint8_t mask;
1380  uint8_t mac[SSH_MAX_HASH_DIGEST_SIZE];
1381 
1382  //Initialize HMAC calculation
1383  hmacInit(decryptionEngine->hmacContext, decryptionEngine->hashAlgo,
1384  decryptionEngine->macKey, decryptionEngine->hashAlgo->digestSize);
1385 
1386  //Compute MAC(key, sequence_number || unencrypted_packet)
1387  hmacUpdate(decryptionEngine->hmacContext, decryptionEngine->seqNum, 4);
1388  hmacUpdate(decryptionEngine->hmacContext, packet, length);
1389  hmacFinal(decryptionEngine->hmacContext, mac);
1390 
1391  //Debug message
1392  TRACE_VERBOSE("Read sequence number:\r\n");
1393  TRACE_VERBOSE_ARRAY(" ", &decryptionEngine->seqNum, 4);
1394  TRACE_VERBOSE("Computed MAC:\r\n");
1395  TRACE_VERBOSE_ARRAY(" ", mac, decryptionEngine->macSize);
1396 
1397  //The calculated MAC is bitwise compared to the received message
1398  //authentication code
1399  for(mask = 0, i = 0; i < decryptionEngine->macSize; i++)
1400  {
1401  mask |= mac[i] ^ packet[length + i];
1402  }
1403 
1404  //The message is authenticated if and only if the MAC values match
1405  return (mask == 0) ? NO_ERROR : ERROR_DECRYPTION_FAILED;
1406 #else
1407  //Not implemented
1408  return ERROR_DECRYPTION_FAILED;
1409 #endif
1410 }
1411 
1412 
1413 /**
1414  * @brief Increment sequence number
1415  * @param[in,out] seqNum Pointer to the 32-bit sequence number
1416  **/
1417 
1419 {
1420  uint16_t temp;
1421 
1422  //Sequence numbers are stored MSB first
1423  temp = seqNum[3] + 1;
1424  seqNum[3] = temp & 0xFF;
1425  temp = (temp >> 8) + seqNum[2];
1426  seqNum[2] = temp & 0xFF;
1427  temp = (temp >> 8) + seqNum[1];
1428  seqNum[1] = temp & 0xFF;
1429  temp = (temp >> 8) + seqNum[0];
1430  seqNum[0] = temp & 0xFF;
1431 }
1432 
1433 
1434 /**
1435  * @brief Increment invocation counter
1436  * @param[in,out] iv Pointer to the 12-octet initialization vector
1437  **/
1438 
1440 {
1441  uint16_t temp;
1442 
1443  //With AES-GCM, the 12-octet IV is broken into two fields: a 4-octet
1444  //fixed field and an 8-octet invocation counter field (refer to RFC 5647,
1445  //section 7.1)
1446  temp = iv[11] + 1;
1447  iv[11] = temp & 0xFF;
1448  temp = (temp >> 8) + iv[10];
1449  iv[10] = temp & 0xFF;
1450  temp = (temp >> 8) + iv[9];
1451  iv[9] = temp & 0xFF;
1452  temp = (temp >> 8) + iv[8];
1453  iv[8] = temp & 0xFF;
1454  temp = (temp >> 8) + iv[7];
1455  iv[7] = temp & 0xFF;
1456  temp = (temp >> 8) + iv[6];
1457  iv[6] = temp & 0xFF;
1458  temp = (temp >> 8) + iv[5];
1459  iv[5] = temp & 0xFF;
1460  temp = (temp >> 8) + iv[4];
1461  iv[4] = temp & 0xFF;
1462 }
1463 
1464 #endif
error_t sshDecryptPacketLength(SshConnection *connection, uint8_t *packet)
Decrypt the length field of an incoming SSH packet.
Definition: ssh_packet.c:956
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:1063
#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:143
uint8_t macKey[SSH_MAX_HASH_DIGEST_SIZE]
Integrity key.
Definition: ssh.h:1353
@ ERROR_DECRYPTION_FAILED
Definition: error.h:243
error_t sshParseNewKeys(SshConnection *connection, const uint8_t *message, size_t length)
Parse SSH_MSG_NEWKEYS message.
Definition: ssh_kex.c:1014
uint8_t iv[SSH_MAX_CIPHER_BLOCK_SIZE]
Initialization vector.
Definition: ssh.h:1350
@ ERROR_UNEXPECTED_MESSAGE
Definition: error.h:195
@ CIPHER_MODE_GCM
Definition: crypto.h:1068
const HashAlgo * hashAlgo
Hash algorithm for MAC operations.
Definition: ssh.h:1346
@ ERROR_INVALID_CHANNEL
Definition: error.h:275
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:224
@ SSH_DISCONNECT_MAC_ERROR
Definition: ssh.h:1024
error_t sshParseChannelClose(SshConnection *connection, const uint8_t *message, size_t length)
Parse SSH_MSG_CHANNEL_CLOSE message.
size_t digestSize
Definition: crypto.h:1157
Poly1305 context.
Definition: poly1305.h:48
@ SSH_MSG_CHANNEL_FAILURE
Definition: ssh.h:1008
GcmContext gcmContext
GCM context.
Definition: ssh.h:1356
size_t macSize
Size of the MAC tag, in bytes.
Definition: ssh.h:1348
size_t blockSize
Definition: crypto.h:1195
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:1007
@ SSH_DISCONNECT_HOST_KEY_NOT_VERIFIABLE
Definition: ssh.h:1028
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:1344
@ SSH_MSG_CHANNEL_OPEN_CONFIRMATION
Definition: ssh.h:999
@ SSH_MSG_REQUEST_FAILURE
Definition: ssh.h:997
@ 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:1066
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:1342
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:479
void chachaCipher(ChachaContext *context, const uint8_t *input, uint8_t *output, size_t length)
Encrypt/decrypt data with the ChaCha algorithm.
Definition: chacha.c:192
uint8_t seqNum[4]
Sequence number.
Definition: ssh.h:1354
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:1197
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:276
@ SSH_MSG_CHANNEL_DATA
Definition: ssh.h:1002
@ 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:995
#define SshContext
Definition: ssh.h:892
#define osMemcpy(dest, src, length)
Definition: os_port.h:144
@ SSH_MSG_NEWKEYS
Definition: ssh.h:966
error_t
Error codes.
Definition: error.h:43
uint32_t seqNum
Definition: tcp.h:348
CipherMode cipherMode
Cipher mode of operation.
Definition: ssh.h:1343
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:1724
@ SSH_MSG_CHANNEL_CLOSE
Definition: ssh.h:1005
@ 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:1344
uint8_t encKey[SSH_MAX_ENC_KEY_SIZE]
Encryption key.
Definition: ssh.h:1351
@ ERROR_INVALID_PACKET
Definition: error.h:141
@ SSH_MSG_SERVICE_REQUEST
Definition: ssh.h:961
@ ERROR_FLOW_CONTROL
Definition: error.h:279
CipherAlgoDecryptStream decryptStream
Definition: crypto.h:1198
@ ERROR_INVALID_LENGTH
Definition: error.h:111
bool_t etm
Encrypt-then-MAC.
Definition: ssh.h:1349
@ SSH_MSG_USERAUTH_REQUEST
Definition: ssh.h:985
CipherContext cipherContext
Cipher context.
Definition: ssh.h:1345
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:986
@ SSH_MSG_DEBUG
Definition: ssh.h:960
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:1659
@ SSH_CONN_STATE_CLIENT_ID
Definition: ssh.h:1058
@ SSH_MSG_CHANNEL_OPEN_FAILURE
Definition: ssh.h:1000
@ SSH_MSG_USERAUTH_BANNER
Definition: ssh.h:988
@ SSH_MSG_DISCONNECT
Definition: ssh.h:957
uint8_t length
Definition: tcp.h:375
@ CIPHER_MODE_STREAM
Definition: crypto.h:1061
error_t sshVerifyMessageAuthCode(SshEncryptionEngine *decryptionEngine, const uint8_t *packet, size_t length)
Verify message authentication code.
Definition: ssh_packet.c:1374
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:987
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:796
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:1021
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:119
#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:998
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:1059
@ SSH_MSG_CHANNEL_REQUEST
Definition: ssh.h:1006
uint8_t m
Definition: ndp.h:304
uint8_t n
@ SSH_DISCONNECT_KEY_EXCHANGE_FAILED
Definition: ssh.h:1022
uint8_t payload[]
Definition: ipv6.h:306
#define SshConnection
Definition: ssh.h:896
__weak_func void hmacFinal(HmacContext *context, uint8_t *digest)
Finish the HMAC calculation.
Definition: hmac.c:218
@ SSH_MSG_CHANNEL_EOF
Definition: ssh.h:1004
uint8_t aad[4]
Additional authenticated data.
Definition: ssh.h:1359
@ SSH_MSG_CHANNEL_WINDOW_ADJUST
Definition: ssh.h:1001
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:1418
Common interface for encryption algorithms.
Definition: crypto.h:1191
void sshIncInvocationCounter(uint8_t *iv)
Increment invocation counter.
Definition: ssh_packet.c:1439
error_t sshDecryptPacket(SshConnection *connection, uint8_t *packet, size_t *length)
Decrypt an incoming SSH packet.
Definition: ssh_packet.c:683
error_t sshEncryptPacket(SshConnection *connection, uint8_t *packet, size_t *length)
Encrypt an outgoing SSH packet.
Definition: ssh_packet.c:473
SSH extension negotiation.
@ SSH_MSG_REQUEST_SUCCESS
Definition: ssh.h:996
@ SSH_MSG_IGNORE
Definition: ssh.h:958
void poly1305Final(Poly1305Context *context, uint8_t *tag)
Finalize Poly1305 message-authentication code computation.
Definition: poly1305.c:124
@ SSH_MSG_KEX_MAX
Definition: ssh.h:968
error_t sshReceivePacket(SshConnection *connection)
Receive SSH packet.
Definition: ssh_packet.c:178
@ SSH_MSG_SERVICE_ACCEPT
Definition: ssh.h:962
SSH packet encryption/decryption.
HmacContext * hmacContext
HMAC context.
Definition: ssh.h:1347
@ ERROR_KEY_EXCH_FAILED
Definition: error.h:313
error_t sshParseChannelData(SshConnection *connection, const uint8_t *message, size_t length)
Parse SSH_MSG_CHANNEL_DATA message.
@ SSH_MSG_UNIMPLEMENTED
Definition: ssh.h:959
@ CIPHER_MODE_CHACHA20_POLY1305
Definition: crypto.h:1070
void poly1305Update(Poly1305Context *context, const void *data, size_t length)
Update Poly1305 message-authentication code computation.
Definition: poly1305.c:86
uint16_t payloadLen
Definition: ipv6.h:301
error_t sshParseMessage(SshConnection *connection, const uint8_t *message, size_t length)
Parse SSH message.
Definition: ssh_packet.c:1135
@ SSH_MSG_USERAUTH_MAX
Definition: ssh.h:990
error_t sshParsePacketLength(SshConnection *connection, uint8_t *packet)
Retrieve the length of an incoming SSH packet.
Definition: ssh_packet.c:919
#define PRIuSIZE
unsigned int uint_t
Definition: compiler_port.h:57
@ SSH_MSG_EXT_INFO
Definition: ssh.h:963
#define osMemset(p, value, length)
Definition: os_port.h:138
@ SSH_MSG_USERAUTH_MIN
Definition: ssh.h:989
__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:1114
__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:356
@ SOCKET_FLAG_BREAK_CRLF
Definition: socket.h:141
#define SSH_BUFFER_SIZE
Definition: ssh.h:888
#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:209
uint8_t nonce[]
Definition: ntp_common.h:239
@ ERROR_INVALID_KEY
Definition: error.h:106
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
@ SSH_MSG_KEX_MIN
Definition: ssh.h:967
#define TRACE_VERBOSE(...)
Definition: debug.h:139
@ SSH_MSG_CHANNEL_EXTENDED_DATA
Definition: ssh.h:1003
#define TRACE_VERBOSE_ARRAY(p, a, n)
Definition: debug.h:140
@ SSH_MSG_KEXINIT
Definition: ssh.h:965