ssh_kex.c
Go to the documentation of this file.
1 /**
2  * @file ssh_kex.c
3  * @brief SSH key exchange
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.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_algorithms.h"
37 #include "ssh/ssh_kex.h"
38 #include "ssh/ssh_kex_rsa.h"
39 #include "ssh/ssh_kex_dh.h"
40 #include "ssh/ssh_kex_dh_gex.h"
41 #include "ssh/ssh_kex_ecdh.h"
42 #include "ssh/ssh_kex_hybrid.h"
43 #include "ssh/ssh_packet.h"
44 #include "ssh/ssh_key_material.h"
45 #include "ssh/ssh_exchange_hash.h"
46 #include "ssh/ssh_misc.h"
47 #include "debug.h"
48 
49 //Check SSH stack configuration
50 #if (SSH_SUPPORT == ENABLED)
51 
52 
53 /**
54  * @brief Send SSH_MSG_KEXINIT message
55  * @param[in] connection Pointer to the SSH connection
56  * @return Error code
57  **/
58 
60 {
61  error_t error;
62  size_t length;
63  uint8_t *message;
64  SshContext *context;
65 
66  //Point to the SSH context
67  context = connection->context;
68 
69  //Point to the buffer where to format the message
70  message = connection->buffer + SSH_PACKET_HEADER_SIZE;
71 
72  //Check whether a key re-exchange has been initiated by the peer
73  if(connection->kexInitReceived)
74  {
75  //A new random cookie has already been generated
76  error = NO_ERROR;
77  }
78  else
79  {
80  //Generate a random cookie
81  error = context->prngAlgo->read(context->prngContext, connection->cookie,
83 
84  //Debug message
85  TRACE_DEBUG(" cookie =\r\n");
86  TRACE_DEBUG_ARRAY(" ", connection->cookie, SSH_COOKIE_SIZE);
87  }
88 
89  //Check status code
90  if(!error)
91  {
92  //Format SSH_MSG_KEXINIT message
93  error = sshFormatKexInit(connection, message, &length);
94  }
95 
96  //Check status code
97  if(!error)
98  {
99  //Debug message
100  TRACE_INFO("Sending SSH_MSG_KEXINIT message (%" PRIuSIZE " bytes)...\r\n", length);
102 
103  //Send message
104  error = sshSendPacket(connection, message, length);
105 
106  //Check status code
107  if(!error)
108  {
109  //An SSH_MSG_KEXINIT message has been successfully sent
110  connection->kexInitSent = TRUE;
111 
112  //Check whether a key re-exchange has been initiated by the peer
113  if(connection->kexInitReceived)
114  {
115 #if (SSH_RSA_KEX_SUPPORT == ENABLED)
116  //RSA key exchange algorithm?
117  if(sshIsRsaKexAlgo(connection->kexAlgo))
118  {
119  //The server sends an SSH_MSG_KEXRSA_PUBKEY message
120  connection->state = SSH_CONN_STATE_KEX_RSA_PUB_KEY;
121  }
122  else
123 #endif
124 #if (SSH_DH_KEX_SUPPORT == ENABLED)
125  //Diffie-Hellman key exchange algorithm?
126  if(sshIsDhKexAlgo(connection->kexAlgo))
127  {
128  //The client sends an SSH_MSG_KEX_DH_INIT message
129  connection->state = SSH_CONN_STATE_KEX_DH_INIT;
130  }
131  else
132 #endif
133 #if (SSH_DH_GEX_KEX_SUPPORT == ENABLED)
134  //DH GEX key exchange algorithm?
135  if(sshIsDhGexKexAlgo(connection->kexAlgo))
136  {
137  //The client sends an SSH_MSG_KEY_DH_GEX_REQUEST message
138  connection->state = SSH_CONN_STATE_KEX_DH_GEX_REQUEST;
139  }
140  else
141 #endif
142 #if (SSH_ECDH_KEX_SUPPORT == ENABLED)
143  //ECDH key exchange algorithm?
144  if(sshIsEcdhKexAlgo(connection->kexAlgo))
145  {
146  //The client sends an SSH_MSG_KEX_ECDH_INIT message
147  connection->state = SSH_CONN_STATE_KEX_ECDH_INIT;
148  }
149  else
150 #endif
151 #if (SSH_HYBRID_KEX_SUPPORT == ENABLED)
152  //Post-quantum hybrid key exchange algorithm?
153  if(sshIsHybridKexAlgo(connection->kexAlgo))
154  {
155  //The client sends an SSH_MSG_KEX_HYBRID_INIT message
156  connection->state = SSH_CONN_STATE_KEX_HYBRID_INIT;
157  }
158  else
159 #endif
160  //Unknown key exchange algorithm?
161  {
162  //Report an error
164  }
165  }
166  else
167  {
168  //Check whether SSH operates as a client or a server
169  if(context->mode == SSH_OPERATION_MODE_CLIENT)
170  {
171  //Wait for the server's KEXINIT message
172  connection->state = SSH_CONN_STATE_SERVER_KEX_INIT;
173  }
174  else
175  {
176  //Wait for the client's KEXINIT message
177  connection->state = SSH_CONN_STATE_CLIENT_KEX_INIT;
178  }
179  }
180  }
181  }
182 
183  //Return status code
184  return error;
185 }
186 
187 
188 /**
189  * @brief Send SSH_MSG_NEWKEYS message
190  * @param[in] connection Pointer to the SSH connection
191  * @return Error code
192  **/
193 
195 {
196  error_t error;
197  uint8_t x;
198  size_t length;
199  uint8_t *message;
200 
201  //Point to the buffer where to format the message
202  message = connection->buffer + SSH_PACKET_HEADER_SIZE;
203 
204  //Format SSH_MSG_NEWKEYS message
205  error = sshFormatNewKeys(connection, message, &length);
206 
207  //Check status code
208  if(!error)
209  {
210  //Debug message
211  TRACE_INFO("Sending SSH_MSG_NEWKEYS message (%" PRIuSIZE " bytes)...\r\n", length);
213 
214  //Send message
215  error = sshSendPacket(connection, message, length);
216  }
217 
218  //Check status code
219  if(!error)
220  {
221  //Check whether SSH operates as a client or a server
222  x = (connection->context->mode == SSH_OPERATION_MODE_CLIENT) ? 'A' : 'B';
223 
224  //Release encryption engine
225  sshFreeEncryptionEngine(&connection->encryptionEngine);
226 
227  //The key exchange method specifies how one-time session keys are
228  //generated for encryption and for authentication
229  error = sshInitEncryptionEngine(connection, &connection->encryptionEngine,
230  connection->serverEncAlgo, connection->serverMacAlgo, x);
231  }
232 
233  //Check status code
234  if(!error)
235  {
236  //An SSH_MSG_NEWKEYS message has been successfully sent
237  connection->newKeysSent = TRUE;
238 
239 #if (SSH_KEX_STRICT_SUPPORT == ENABLED)
240  //Strict key exchange?
241  if(connection->kexStrictReceived)
242  {
243  //Reset the packet sequence number to zero
244  osMemset(connection->encryptionEngine.seqNum, 0, 4);
245  }
246 #endif
247 
248 #if (SSH_EXT_INFO_SUPPORT == ENABLED)
249  //If a server receives an "ext-info-c", or a client receives an
250  //"ext-info-s", it may send an SSH_MSG_EXT_INFO message (refer to
251  //RFC 8308, section 2.1)
252  if(!connection->newKeysReceived && connection->extInfoReceived)
253  {
254  //Check whether SSH operates as a client or a server
255  if(connection->context->mode == SSH_OPERATION_MODE_CLIENT)
256  {
257  //If a client sends SSH_MSG_EXT_INFO, it must send it as the next
258  //packet following the client's first SSH_MSG_NEWKEYS message
259  connection->state = SSH_CONN_STATE_CLIENT_EXT_INFO;
260  }
261  else
262  {
263  //The server may send the SSH_MSG_EXT_INFO message as the next packet
264  //following the server's first SSH_MSG_NEWKEYS message
265  connection->state = SSH_CONN_STATE_SERVER_EXT_INFO_1;
266  }
267  }
268  else
269 #endif
270  {
271  //Check whether SSH operates as a client or a server
272  if(connection->context->mode == SSH_OPERATION_MODE_CLIENT)
273  {
274  //Wait for the server's SSH_MSG_NEWKEYS message
275  connection->state = SSH_CONN_STATE_SERVER_NEW_KEYS;
276  }
277  else
278  {
279  //Wait for the client's SSH_MSG_NEWKEYS message
280  connection->state = SSH_CONN_STATE_CLIENT_NEW_KEYS;
281  }
282  }
283  }
284 
285  //Return status code
286  return error;
287 }
288 
289 
290 /**
291  * @brief Format SSH_MSG_KEXINIT message
292  * @param[in] connection Pointer to the SSH connection
293  * @param[out] p Buffer where to format the message
294  * @param[out] length Length of the resulting message, in bytes
295  * @return Error code
296  **/
297 
298 error_t sshFormatKexInit(SshConnection *connection, uint8_t *p,
299  size_t *length)
300 {
301  error_t error;
302  size_t n;
303  SshContext *context;
304 
305  //Point to the SSH context
306  context = connection->context;
307 
308  //Total length of the message
309  *length = 0;
310 
311  //Set message type
312  p[0] = SSH_MSG_KEXINIT;
313 
314  //Point to the first field of the message
315  p += sizeof(uint8_t);
316  *length += sizeof(uint8_t);
317 
318  //The cookie is a random value generated by the sender
319  osMemcpy(p, connection->cookie, SSH_COOKIE_SIZE);
320 
321  //Point to the next field
322  p += SSH_COOKIE_SIZE;
324 
325  //Format the list of key exchange algorithms
326  error = sshFormatKexAlgoList(connection, p, &n);
327  //Any error to report?
328  if(error)
329  return error;
330 
331  //Point to the next field
332  p += n;
333  *length += n;
334 
335  //Format the list of host key algorithms
336  error = sshFormatHostKeyAlgoList(context, p, &n);
337  //Any error to report?
338  if(error)
339  return error;
340 
341  //Point to the next field
342  p += n;
343  *length += n;
344 
345  //Format the list of encryption algorithms (client to server)
346  error = sshFormatEncAlgoList(context, p, &n);
347  //Any error to report?
348  if(error)
349  return error;
350 
351  //Point to the next field
352  p += n;
353  *length += n;
354 
355  //Format the list of encryption algorithms (server to client)
356  error = sshFormatEncAlgoList(context, p, &n);
357  //Any error to report?
358  if(error)
359  return error;
360 
361  //Point to the next field
362  p += n;
363  *length += n;
364 
365  //Format the list of MAC algorithms (client to server)
366  error = sshFormatMacAlgoList(context, p, &n);
367  //Any error to report?
368  if(error)
369  return error;
370 
371  //Point to the next field
372  p += n;
373  *length += n;
374 
375  //Format the list of MAC algorithms (server to client)
376  error = sshFormatMacAlgoList(context, p, &n);
377  //Any error to report?
378  if(error)
379  return error;
380 
381  //Point to the next field
382  p += n;
383  *length += n;
384 
385  //Format the list of compression algorithms (client to server)
386  error = sshFormatCompressionAlgoList(context, p, &n);
387  //Any error to report?
388  if(error)
389  return error;
390 
391  //Point to the next field
392  p += n;
393  *length += n;
394 
395  //Format the list of compression algorithms (server to client)
396  error = sshFormatCompressionAlgoList(context, p, &n);
397  //Any error to report?
398  if(error)
399  return error;
400 
401  //Point to the next field
402  p += n;
403  *length += n;
404 
405  //Format the list of language tags (client to server)
406  STORE32BE(0, p);
407 
408  //Point to the next field
409  p += sizeof(uint32_t);
410  *length += sizeof(uint32_t);
411 
412  //Format the list of language tags (server to client)
413  STORE32BE(0, p);
414 
415  //Point to the next field
416  p += sizeof(uint32_t);
417  *length += sizeof(uint32_t);
418 
419  //The first_kex_packet_follows field indicates whether a guessed key
420  //exchange packet follows. If no guessed packet will be sent, this must
421  //be FALSE (refer to RFC 4253, section 7.1)
422  p[0] = FALSE;
423 
424  //Point to the next field
425  p += sizeof(uint8_t);
426  *length += sizeof(uint8_t);
427 
428  //This field is reserved for future extension
429  STORE32BE(0, p);
430 
431  //Total length of the message
432  *length += sizeof(uint32_t);
433 
434  //Successful processing
435  return NO_ERROR;
436 }
437 
438 
439 /**
440  * @brief Format SSH_MSG_NEWKEYS message
441  * @param[in] connection Pointer to the SSH connection
442  * @param[out] p Buffer where to format the message
443  * @param[out] length Length of the resulting message, in bytes
444  * @return Error code
445  **/
446 
447 error_t sshFormatNewKeys(SshConnection *connection, uint8_t *p,
448  size_t *length)
449 {
450  //The SSH_MSG_NEWKEYS message consists of a single byte
451  p[0] = SSH_MSG_NEWKEYS;
452 
453  //Total length of the message
454  *length = sizeof(uint8_t);
455 
456  //Successful processing
457  return NO_ERROR;
458 }
459 
460 
461 /**
462  * @brief Parse SSH_MSG_KEXINIT message
463  * @param[in] connection Pointer to the SSH connection
464  * @param[in] message Pointer to message
465  * @param[in] length Length of the message, in bytes
466  * @return Error code
467  **/
468 
469 error_t sshParseKexInit(SshConnection *connection, const uint8_t *message,
470  size_t length)
471 {
472  error_t error;
473  size_t n;
474  const uint8_t *p;
475  SshNameList nameList;
476  SshNameList kexAlgoList;
477  SshNameList hostKeyAlgoList;
478  SshBoolean firstKexPacketFollows;
479  SshContext *context;
480 
481  //Point to the SSH context
482  context = connection->context;
483 
484  //Debug message
485  TRACE_INFO("SSH_MSG_KEXINIT message received (%" PRIuSIZE " bytes)...\r\n", length);
487 
488  //Check whether SSH operates as a client or a server
489  if(context->mode == SSH_OPERATION_MODE_CLIENT)
490  {
491  //Check connection state
492  if(connection->state != SSH_CONN_STATE_SERVER_KEX_INIT &&
493  connection->state != SSH_CONN_STATE_OPEN)
494  {
495  //Report an error
497  }
498  }
499  else
500  {
501  //Check connection state
502  if(connection->state != SSH_CONN_STATE_CLIENT_KEX_INIT &&
503  connection->state != SSH_CONN_STATE_OPEN)
504  {
505  //Report an error
507  }
508  }
509 
510  //Sanity check
511  if(length < sizeof(uint8_t))
512  return ERROR_INVALID_MESSAGE;
513 
514  //Point to the first field of the message
515  p = message + sizeof(uint8_t);
516  //Remaining bytes to process
517  n = length - sizeof(uint8_t);
518 
519  //Maformed message?
520  if(length < SSH_COOKIE_SIZE)
521  return ERROR_INVALID_MESSAGE;
522 
523  //Debug message
524  TRACE_DEBUG(" cookie =\r\n");
526 
527  //Point to the next field
528  p += SSH_COOKIE_SIZE;
529  n -= SSH_COOKIE_SIZE;
530 
531  //Decode the kex_algorithms field
532  error = sshParseNameList(p, n, &kexAlgoList);
533  //Any error to report?
534  if(error)
535  return error;
536 
537  //Debug message
538  TRACE_DEBUG(" kex_algorithms =\r\n");
539  TRACE_DEBUG("%s\r\n\r\n", kexAlgoList.value);
540 
541  //Select key exchange algorithm
542  connection->kexAlgo = sshSelectKexAlgo(connection, &kexAlgoList);
543  //No matching algorithm found?
544  if(connection->kexAlgo == NULL)
545  return ERROR_UNSUPPORTED_ALGO;
546 
547  //Point to the next field
548  p += sizeof(uint32_t) + kexAlgoList.length;
549  n -= sizeof(uint32_t) + kexAlgoList.length;
550 
551  //Decode the server_host_key_algorithms field
552  error = sshParseNameList(p, n, &hostKeyAlgoList);
553  //Any error to report?
554  if(error)
555  return error;
556 
557  //Debug message
558  TRACE_DEBUG(" server_host_key_algorithms =\r\n");
559  TRACE_DEBUG("%s\r\n\r\n", hostKeyAlgoList.value);
560 
561  //Select host key algorithm
562  connection->serverHostKeyAlgo = sshSelectHostKeyAlgo(context,
563  &hostKeyAlgoList);
564  //No matching algorithm found?
565  if(connection->serverHostKeyAlgo == NULL)
566  return ERROR_UNSUPPORTED_ALGO;
567 
568  //Server operation mode?
569  if(context->mode == SSH_OPERATION_MODE_SERVER)
570  {
571  //Select the host key to use
572  connection->hostKeyIndex = sshSelectHostKey(context,
573  connection->serverHostKeyAlgo);
574 
575  //No matching host key found?
576  if(connection->hostKeyIndex < 0)
577  return ERROR_UNSUPPORTED_ALGO;
578  }
579 
580  //Point to the next field
581  p += sizeof(uint32_t) + hostKeyAlgoList.length;
582  n -= sizeof(uint32_t) + hostKeyAlgoList.length;
583 
584  //Decode the encryption_algorithms_client_to_server field
585  error = sshParseNameList(p, n, &nameList);
586  //Any error to report?
587  if(error)
588  return error;
589 
590  //Debug message
591  TRACE_DEBUG(" encryption_algorithms_client_to_server =\r\n");
592  TRACE_DEBUG("%s\r\n\r\n", nameList.value);
593 
594  //Select encryption algorithm (client to server)
595  connection->clientEncAlgo = sshSelectEncAlgo(context, &nameList);
596  //No matching algorithm found?
597  if(connection->clientEncAlgo == NULL)
598  return ERROR_UNSUPPORTED_ALGO;
599 
600  //Point to the next field
601  p += sizeof(uint32_t) + nameList.length;
602  n -= sizeof(uint32_t) + nameList.length;
603 
604  //Decode the encryption_algorithms_server_to_client field
605  error = sshParseNameList(p, n, &nameList);
606  //Any error to report?
607  if(error)
608  return error;
609 
610  //Debug message
611  TRACE_VERBOSE(" encryption_algorithms_server_to_client =\r\n");
612  TRACE_VERBOSE("%s\r\n\r\n", nameList.value);
613 
614  //Select encryption algorithm (server to client)
615  connection->serverEncAlgo = sshSelectEncAlgo(context, &nameList);
616  //No matching algorithm found?
617  if(connection->serverEncAlgo == NULL)
618  return ERROR_UNSUPPORTED_ALGO;
619 
620  //Point to the next field
621  p += sizeof(uint32_t) + nameList.length;
622  n -= sizeof(uint32_t) + nameList.length;
623 
624  //Decode the mac_algorithms_client_to_server field
625  error = sshParseNameList(p, n, &nameList);
626  //Any error to report?
627  if(error)
628  return error;
629 
630  //Debug message
631  TRACE_DEBUG(" mac_algorithms_client_to_server =\r\n");
632  TRACE_DEBUG("%s\r\n\r\n", nameList.value);
633 
634  //Select MAC algorithm (client to server)
635  connection->clientMacAlgo = sshSelectMacAlgo(context,
636  connection->clientEncAlgo, &nameList);
637  //No matching algorithm found?
638  if(connection->clientMacAlgo == NULL)
639  return ERROR_UNSUPPORTED_ALGO;
640 
641 #if (SSH_RFC5647_SUPPORT == ENABLED)
642  //If AES-GCM is selected as the MAC algorithm, it must also be selected as
643  //the encryption algorithm (refer to RFC 5647, section 5.1)
644  if(sshCompareAlgo(connection->clientMacAlgo, "AEAD_AES_128_GCM") ||
645  sshCompareAlgo(connection->clientMacAlgo, "AEAD_AES_256_GCM") ||
646  sshCompareAlgo(connection->clientMacAlgo, "AEAD_CAMELLIA_128_GCM") ||
647  sshCompareAlgo(connection->clientMacAlgo, "AEAD_CAMELLIA_256_GCM"))
648  {
649  //AEAD algorithms offer both encryption and authentication
650  connection->clientEncAlgo = connection->clientMacAlgo;
651  }
652 #endif
653 
654  //Point to the next field
655  p += sizeof(uint32_t) + nameList.length;
656  n -= sizeof(uint32_t) + nameList.length;
657 
658  //Decode the mac_algorithms_server_to_client field
659  error = sshParseNameList(p, n, &nameList);
660  //Any error to report?
661  if(error)
662  return error;
663 
664  //Debug message
665  TRACE_VERBOSE(" mac_algorithms_server_to_client =\r\n");
666  TRACE_VERBOSE("%s\r\n\r\n", nameList.value);
667 
668  //Select MAC algorithm (server to client)
669  connection->serverMacAlgo = sshSelectMacAlgo(context,
670  connection->serverEncAlgo, &nameList);
671  //No matching algorithm found?
672  if(connection->serverMacAlgo == NULL)
673  return ERROR_UNSUPPORTED_ALGO;
674 
675 #if (SSH_RFC5647_SUPPORT == ENABLED)
676  //If AES-GCM is selected as the MAC algorithm, it must also be selected as
677  //the encryption algorithm (refer to RFC 5647, section 5.1)
678  if(sshCompareAlgo(connection->serverMacAlgo, "AEAD_AES_128_GCM") ||
679  sshCompareAlgo(connection->serverMacAlgo, "AEAD_AES_256_GCM") ||
680  sshCompareAlgo(connection->serverMacAlgo, "AEAD_CAMELLIA_128_GCM") ||
681  sshCompareAlgo(connection->serverMacAlgo, "AEAD_CAMELLIA_256_GCM"))
682  {
683  //AEAD algorithms offer both encryption and authentication
684  connection->serverEncAlgo = connection->serverMacAlgo;
685  }
686 #endif
687 
688  //Point to the next field
689  p += sizeof(uint32_t) + nameList.length;
690  n -= sizeof(uint32_t) + nameList.length;
691 
692  //Decode the compression_algorithms_client_to_server field
693  error = sshParseNameList(p, n, &nameList);
694  //Any error to report?
695  if(error)
696  return error;
697 
698  //Debug message
699  TRACE_VERBOSE(" compression_algorithms_client_to_server =\r\n");
700  TRACE_VERBOSE("%s\r\n\r\n", nameList.value);
701 
702  //Select compression algorithm (client to server)
703  connection->clientCompressAlgo = sshSelectCompressionAlgo(context,
704  &nameList);
705  //No matching algorithm found?
706  if(connection->clientCompressAlgo == NULL)
707  return ERROR_UNSUPPORTED_ALGO;
708 
709  //Point to the next field
710  p += sizeof(uint32_t) + nameList.length;
711  n -= sizeof(uint32_t) + nameList.length;
712 
713  //Decode the compression_algorithms_server_to_client field
714  error = sshParseNameList(p, n, &nameList);
715  //Any error to report?
716  if(error)
717  return error;
718 
719  //Debug message
720  TRACE_VERBOSE(" compression_algorithms_server_to_client =\r\n");
721  TRACE_VERBOSE("%s\r\n\r\n", nameList.value);
722 
723  //Select compression algorithm (server to client)
724  connection->serverCompressAlgo = sshSelectCompressionAlgo(context,
725  &nameList);
726  //No matching algorithm found?
727  if(connection->serverCompressAlgo == NULL)
728  return ERROR_UNSUPPORTED_ALGO;
729 
730  //Point to the next field
731  p += sizeof(uint32_t) + nameList.length;
732  n -= sizeof(uint32_t) + nameList.length;
733 
734  //Decode the languages_client_to_server field
735  error = sshParseNameList(p, n, &nameList);
736  //Any error to report?
737  if(error)
738  return error;
739 
740  //Debug message
741  TRACE_VERBOSE(" languages_client_to_server =\r\n");
742  TRACE_VERBOSE("%s\r\n\r\n", nameList.value);
743 
744  //Point to the next field
745  p += sizeof(uint32_t) + nameList.length;
746  n -= sizeof(uint32_t) + nameList.length;
747 
748  //Decode the languages_server_to_client field
749  error = sshParseNameList(p, n, &nameList);
750  //Any error to report?
751  if(error)
752  return error;
753 
754  //Debug message
755  TRACE_VERBOSE(" languages_server_to_client =\r\n");
756  TRACE_VERBOSE("%s\r\n\r\n", nameList.value);
757 
758  //Point to the next field
759  p += sizeof(uint32_t) + nameList.length;
760  n -= sizeof(uint32_t) + nameList.length;
761 
762  //Malformed message?
763  if(n < sizeof(uint8_t))
764  return ERROR_INVALID_MESSAGE;
765 
766  //Retrieve the value of the first_kex_packet_follows field
767  firstKexPacketFollows = p[0];
768 
769  //Point to the next field
770  p += sizeof(uint8_t);
771  n -= sizeof(uint8_t);
772 
773  //Malformed message?
774  if(n < sizeof(uint32_t))
775  return ERROR_INVALID_MESSAGE;
776 
777  //Ignore the reserved field
778  p += sizeof(uint32_t);
779  n -= sizeof(uint32_t);
780 
781  //Malformed message?
782  if(n != 0)
783  return ERROR_INVALID_MESSAGE;
784 
785  //An SSH_MSG_KEXINIT message has been successfully received
786  connection->kexInitReceived = TRUE;
787 
788  //Debug message
789  TRACE_INFO(" Selected kex algo = %s\r\n", connection->kexAlgo);
790  TRACE_INFO(" Selected server host key algo = %s\r\n", connection->serverHostKeyAlgo);
791  TRACE_INFO(" Selected client enc algo = %s\r\n", connection->clientEncAlgo);
792  TRACE_INFO(" Selected client mac algo = %s\r\n", connection->clientMacAlgo);
793  TRACE_INFO(" Selected server enc algo = %s\r\n", connection->serverEncAlgo);
794  TRACE_INFO(" Selected server mac algo = %s\r\n", connection->serverMacAlgo);
795 
796  //The first_kex_packet_follows field indicates whether a guessed key
797  //exchange packet follows
798  if(firstKexPacketFollows)
799  {
800  //The guess is considered wrong if the key exchange algorithm or the host
801  //key algorithm is guessed wrong (refer to RFC 4253, section 7)
802  if(!sshIsGuessCorrect(context, &kexAlgoList, &hostKeyAlgoList))
803  {
804  //If the other party's guess was wrong, the next packet must be
805  //silently ignored, and both sides must then act as determined by
806  //the negotiated key exchange method
807  connection->wrongGuess = TRUE;
808  }
809  else
810  {
811  //If the guess was right, key exchange must continue using the guessed
812  //packet
813  connection->wrongGuess = FALSE;
814  }
815  }
816  else
817  {
818  //No guessed packet will be sent
819  connection->wrongGuess = FALSE;
820  }
821 
822  //Initialize exchange hash H
823  error = sshInitExchangeHash(connection);
824  //Any error to report?
825  if(error)
826  return error;
827 
828  //Update exchange hash H with V_C (client's identification string)
829  error = sshUpdateExchangeHash(connection, connection->clientId,
830  osStrlen(connection->clientId));
831  //Any error to report?
832  if(error)
833  return error;
834 
835  //Update exchange hash H with V_S (server's identification string)
836  error = sshUpdateExchangeHash(connection, connection->serverId,
837  osStrlen(connection->serverId));
838  //Any error to report?
839  if(error)
840  return error;
841 
842  //Check whether a key re-exchange has been initiated by the peer
843  if(!connection->kexInitSent)
844  {
845  //Generate a random cookie
846  error = context->prngAlgo->read(context->prngContext, connection->cookie,
848  //Any error to report?
849  if(error)
850  return error;
851 
852  //Debug message
853  TRACE_DEBUG(" cookie =\r\n");
854  TRACE_DEBUG_ARRAY(" ", connection->cookie, SSH_COOKIE_SIZE);
855  }
856 
857  //Check whether SSH operates as a client or a server
858  if(context->mode == SSH_OPERATION_MODE_CLIENT)
859  {
860  //Update exchange hash H with I_C (payload of the client's SSH_MSG_KEXINIT)
861  error = sshDigestClientKexInit(connection);
862  //Any error to report?
863  if(error)
864  return error;
865 
866  //Update exchange hash H with I_S (payload of the server's SSH_MSG_KEXINIT)
867  error = sshUpdateExchangeHash(connection, message, length);
868  //Any error to report?
869  if(error)
870  return error;
871  }
872  else
873  {
874  //Update exchange hash H with I_C (payload of the client's SSH_MSG_KEXINIT)
875  error = sshUpdateExchangeHash(connection, message, length);
876  //Any error to report?
877  if(error)
878  return error;
879 
880  //Format SSH_MSG_KEXINIT message
881  error = sshFormatKexInit(connection, connection->buffer, &n);
882  //Any error to report?
883  if(error)
884  return error;
885 
886  //Debug message
887  TRACE_VERBOSE_ARRAY("I_S = ", connection->buffer, n);
888 
889  //Update exchange hash H with I_S (payload of the server's SSH_MSG_KEXINIT)
890  error = sshUpdateExchangeHash(connection, connection->buffer, n);
891  //Any error to report?
892  if(error)
893  return error;
894 
895  //Format server's public host key
896  error = sshFormatHostKey(connection, connection->buffer, &n);
897  //Any error to report?
898  if(error)
899  return error;
900 
901  //Debug message
902  TRACE_VERBOSE_ARRAY("K_S = ", connection->buffer, n);
903 
904  //Update exchange hash H with K_S (server's public host key)
905  error = sshUpdateExchangeHash(connection, connection->buffer, n);
906  //Any error to report?
907  if(error)
908  return error;
909  }
910 
911  //Check whether a key re-exchange has been initiated by the peer
912  if(!connection->kexInitSent)
913  {
914  //Either party may initiate the re-exchange by sending an SSH_MSG_KEXINIT
915  //message. When this message is received, a party must respond with its
916  //own SSH_MSG_KEXINIT message (refer to RFC 4253, section 9)
917  if(context->mode == SSH_OPERATION_MODE_CLIENT)
918  {
919  //The client responds with a KEXINIT message
920  connection->state = SSH_CONN_STATE_CLIENT_KEX_INIT;
921  }
922  else
923  {
924  //The server responds with a KEXINIT message
925  connection->state = SSH_CONN_STATE_SERVER_KEX_INIT;
926  }
927  }
928  else
929  {
930 #if (SSH_RSA_KEX_SUPPORT == ENABLED)
931  //RSA key exchange algorithm?
932  if(sshIsRsaKexAlgo(connection->kexAlgo))
933  {
934  //The server sends an SSH_MSG_KEXRSA_PUBKEY message
935  connection->state = SSH_CONN_STATE_KEX_RSA_PUB_KEY;
936  }
937  else
938 #endif
939 #if (SSH_DH_KEX_SUPPORT == ENABLED)
940  //Diffie-Hellman key exchange algorithm?
941  if(sshIsDhKexAlgo(connection->kexAlgo))
942  {
943  //The client sends an SSH_MSG_KEX_DH_INIT message
944  connection->state = SSH_CONN_STATE_KEX_DH_INIT;
945  }
946  else
947 #endif
948 #if (SSH_DH_GEX_KEX_SUPPORT == ENABLED)
949  //DH GEX key exchange algorithm?
950  if(sshIsDhGexKexAlgo(connection->kexAlgo))
951  {
952  //The client sends an SSH_MSG_KEY_DH_GEX_REQUEST message
953  connection->state = SSH_CONN_STATE_KEX_DH_GEX_REQUEST;
954  }
955  else
956 #endif
957 #if (SSH_ECDH_KEX_SUPPORT == ENABLED)
958  //ECDH key exchange algorithm?
959  if(sshIsEcdhKexAlgo(connection->kexAlgo))
960  {
961  //The client sends an SSH_MSG_KEX_ECDH_INIT message
962  connection->state = SSH_CONN_STATE_KEX_ECDH_INIT;
963  }
964  else
965 #endif
966 #if (SSH_HYBRID_KEX_SUPPORT == ENABLED)
967  //Post-quantum hybrid key exchange algorithm?
968  if(sshIsHybridKexAlgo(connection->kexAlgo))
969  {
970  //The client sends an SSH_MSG_KEX_HYBRID_INIT message
971  connection->state = SSH_CONN_STATE_KEX_HYBRID_INIT;
972  }
973  else
974 #endif
975  //Unknown key exchange algorithm?
976  {
977  //Report an error
979  }
980  }
981 
982  //Return status code
983  return error;
984 }
985 
986 
987 /**
988  * @brief Parse SSH_MSG_NEWKEYS message
989  * @param[in] connection Pointer to the SSH connection
990  * @param[in] message Pointer to message
991  * @param[in] length Length of the message, in bytes
992  * @return Error code
993  **/
994 
995 error_t sshParseNewKeys(SshConnection *connection, const uint8_t *message,
996  size_t length)
997 {
998  error_t error;
999  uint8_t x;
1000 
1001  //Debug message
1002  TRACE_INFO("SSH_MSG_NEWKEYS message received (%" PRIuSIZE " bytes)...\r\n", length);
1004 
1005  //Check whether SSH operates as a client or a server
1006  if(connection->context->mode == SSH_OPERATION_MODE_CLIENT)
1007  {
1008  //Check connection state
1009  if(connection->state != SSH_CONN_STATE_SERVER_NEW_KEYS)
1010  return ERROR_UNEXPECTED_MESSAGE;
1011  }
1012  else
1013  {
1014  //Check connection state
1015  if(connection->state != SSH_CONN_STATE_CLIENT_NEW_KEYS)
1016  return ERROR_UNEXPECTED_MESSAGE;
1017  }
1018 
1019  //The SSH_MSG_NEWKEYS message consists of a single byte
1020  if(length != sizeof(uint8_t))
1021  return ERROR_INVALID_MESSAGE;
1022 
1023  //Check whether SSH operates as a client or a server
1024  x = (connection->context->mode == SSH_OPERATION_MODE_CLIENT) ? 'B' : 'A';
1025 
1026  //Release decryption engine
1027  sshFreeEncryptionEngine(&connection->decryptionEngine);
1028 
1029  //The key exchange method specifies how one-time session keys are generated
1030  //for encryption and for authentication
1031  error = sshInitEncryptionEngine(connection, &connection->decryptionEngine,
1032  connection->clientEncAlgo, connection->clientMacAlgo, x);
1033 
1034  //Check status code
1035  if(!error)
1036  {
1037 #if (SSH_KEX_STRICT_SUPPORT == ENABLED)
1038  //Strict key exchange?
1039  if(connection->kexStrictReceived)
1040  {
1041  //Reset the packet sequence number to zero
1042  osMemset(connection->decryptionEngine.seqNum, 0xFF, 4);
1043  }
1044 #endif
1045 
1046  //Key re-exchange?
1047  if(connection->newKeysReceived)
1048  {
1049  //Either party may later initiate a key re-exchange by sending a
1050  //SSH_MSG_KEXINIT message
1051  connection->kexInitSent = FALSE;
1052  connection->kexInitReceived = FALSE;
1053 
1054  //The SSH_MSG_USERAUTH_SUCCESS message must be sent only once. When
1055  //SSH_MSG_USERAUTH_SUCCESS has been sent, any further authentication
1056  //requests received after that should be silently ignored
1057  connection->state = SSH_CONN_STATE_OPEN;
1058  }
1059  else
1060  {
1061  //An SSH_MSG_NEWKEYS message has been successfully received
1062  connection->newKeysReceived = TRUE;
1063 
1064 #if (SSH_EXT_INFO_SUPPORT == ENABLED)
1065  //Server operation mode?
1066  if(connection->context->mode == SSH_OPERATION_MODE_SERVER)
1067  {
1068  //If a client sends SSH_MSG_EXT_INFO, it must send it as the next
1069  //packet following the client's first SSH_MSG_NEWKEYS message
1070  connection->state = SSH_CONN_STATE_CLIENT_EXT_INFO;
1071  }
1072  else
1073 #endif
1074  {
1075  //After the key exchange, the client requests a service
1076  connection->state = SSH_CONN_STATE_SERVICE_REQUEST;
1077  }
1078  }
1079  }
1080 
1081  //Return status code
1082  return error;
1083 }
1084 
1085 
1086 /**
1087  * @brief Parse key exchange method-specific messages
1088  * @param[in] connection Pointer to the SSH connection
1089  * @param[in] type SSH message type
1090  * @param[in] message Pointer to message
1091  * @param[in] length Length of the message, in bytes
1092  * @return Error code
1093  **/
1094 
1096  const uint8_t *message, size_t length)
1097 {
1098  error_t error;
1099 
1100  //Check if the other party's guess was wrong
1101  if(connection->wrongGuess)
1102  {
1103  //Debug message
1104  TRACE_INFO("Discarding wrong guessed packet(%" PRIuSIZE " bytes)...\r\n", length);
1106 
1107  //If the guess was wrong, the packet must be silently ignored and both
1108  //sides must then act as determined by the negotiated key exchange method
1109  connection->wrongGuess = FALSE;
1110 
1111  //Continue processing
1112  error = NO_ERROR;
1113  }
1114  else
1115  {
1116 #if (SSH_RSA_KEX_SUPPORT == ENABLED)
1117  //RSA key exchange algorithm?
1118  if(sshIsRsaKexAlgo(connection->kexAlgo))
1119  {
1120  //Parse RSA specific messages
1121  error = sshParseKexRsaMessage(connection, type, message, length);
1122  }
1123  else
1124 #endif
1125 #if (SSH_DH_KEX_SUPPORT == ENABLED)
1126  //Diffie-Hellman key exchange algorithm?
1127  if(sshIsDhKexAlgo(connection->kexAlgo))
1128  {
1129  //Parse Diffie-Hellman specific messages
1130  error = sshParseKexDhMessage(connection, type, message, length);
1131  }
1132  else
1133 #endif
1134 #if (SSH_DH_GEX_KEX_SUPPORT == ENABLED)
1135  //DH GEX key exchange algorithm?
1136  if(sshIsDhGexKexAlgo(connection->kexAlgo))
1137  {
1138  //Parse Diffie-Hellman Group Exchange specific messages
1139  error = sshParseKexDhGexMessage(connection, type, message, length);
1140  }
1141  else
1142 #endif
1143 #if (SSH_ECDH_KEX_SUPPORT == ENABLED)
1144  //ECDH key exchange algorithm?
1145  if(sshIsEcdhKexAlgo(connection->kexAlgo))
1146  {
1147  //Parse ECDH specific messages
1148  error = sshParseKexEcdhMessage(connection, type, message, length);
1149  }
1150  else
1151 #endif
1152 #if (SSH_HYBRID_KEX_SUPPORT == ENABLED)
1153  //Post-quantum hybrid key exchange algorithm?
1154  if(sshIsHybridKexAlgo(connection->kexAlgo))
1155  {
1156  //Parse PQ-hybrid specific messages
1157  error = sshParseKexHybridMessage(connection, type, message, length);
1158  }
1159  else
1160 #endif
1161  //Unknown key exchange algorithm?
1162  {
1163  //Report an error
1165  }
1166  }
1167 
1168  //Return status code
1169  return error;
1170 }
1171 
1172 
1173 /**
1174  * @brief Update exchange hash with client's SSH_MSG_KEXINIT message
1175  * @param[in] connection Pointer to the SSH connection
1176  * @return Error code
1177  **/
1178 
1180 {
1181  error_t error;
1182  size_t n;
1183  uint8_t *buffer;
1184 
1185  //Allocate a temporary buffer
1186  buffer = sshAllocMem(SSH_BUFFER_SIZE);
1187 
1188  //Successful memory allocation?
1189  if(buffer != NULL)
1190  {
1191  //Format SSH_MSG_KEXINIT message
1192  error = sshFormatKexInit(connection, buffer, &n);
1193 
1194  //Check status code
1195  if(!error)
1196  {
1197  //Debug message
1198  TRACE_VERBOSE_ARRAY("I_C = ", buffer, n);
1199 
1200  //Update exchange hash H with I_C (payload of the client's
1201  //SSH_MSG_KEXINIT)
1202  error = sshUpdateExchangeHash(connection, buffer, n);
1203  }
1204 
1205  //Release previously allocated memory
1206  sshFreeMem(buffer);
1207  }
1208  else
1209  {
1210  //Failed to allocate memory
1211  error = ERROR_OUT_OF_MEMORY;
1212  }
1213 
1214  //Return status code
1215  return error;
1216 }
1217 
1218 #endif
uint8_t message[]
Definition: chap.h:154
uint8_t type
Definition: coap_common.h:176
#define PRIuSIZE
#define STORE32BE(a, p)
Definition: cpu_endian.h:286
Debugging facilities.
#define TRACE_DEBUG_ARRAY(p, a, n)
Definition: debug.h:108
#define TRACE_DEBUG(...)
Definition: debug.h:107
#define TRACE_VERBOSE(...)
Definition: debug.h:124
#define TRACE_INFO(...)
Definition: debug.h:95
#define TRACE_VERBOSE_ARRAY(p, a, n)
Definition: debug.h:125
uint8_t n
error_t
Error codes.
Definition: error.h:43
@ ERROR_UNSUPPORTED_KEY_EXCH_ALGO
Definition: error.h:131
@ ERROR_INVALID_MESSAGE
Definition: error.h:105
@ ERROR_UNSUPPORTED_ALGO
Definition: error.h:126
@ NO_ERROR
Success.
Definition: error.h:44
@ ERROR_OUT_OF_MEMORY
Definition: error.h:63
@ ERROR_UNEXPECTED_MESSAGE
Definition: error.h:194
uint8_t x
Definition: lldp_ext_med.h:211
uint8_t p
Definition: ndp.h:300
#define osMemset(p, value, length)
Definition: os_port.h:135
#define osMemcpy(dest, src, length)
Definition: os_port.h:141
#define osStrlen(s)
Definition: os_port.h:165
#define TRUE
Definition: os_port.h:50
#define FALSE
Definition: os_port.h:46
Secure Shell (SSH)
#define sshFreeMem(p)
Definition: ssh.h:736
#define SSH_COOKIE_SIZE
Definition: ssh.h:868
@ SSH_CONN_STATE_OPEN
Definition: ssh.h:1071
@ SSH_CONN_STATE_CLIENT_EXT_INFO
Definition: ssh.h:1062
@ SSH_CONN_STATE_SERVER_KEX_INIT
Definition: ssh.h:1046
@ SSH_CONN_STATE_KEX_ECDH_INIT
Definition: ssh.h:1056
@ SSH_CONN_STATE_KEX_RSA_PUB_KEY
Definition: ssh.h:1047
@ SSH_CONN_STATE_KEX_DH_GEX_REQUEST
Definition: ssh.h:1052
@ SSH_CONN_STATE_CLIENT_NEW_KEYS
Definition: ssh.h:1060
@ SSH_CONN_STATE_CLIENT_KEX_INIT
Definition: ssh.h:1045
@ SSH_CONN_STATE_KEX_DH_INIT
Definition: ssh.h:1050
@ SSH_CONN_STATE_SERVICE_REQUEST
Definition: ssh.h:1065
@ SSH_CONN_STATE_SERVER_EXT_INFO_1
Definition: ssh.h:1063
@ SSH_CONN_STATE_SERVER_NEW_KEYS
Definition: ssh.h:1061
@ SSH_CONN_STATE_KEX_HYBRID_INIT
Definition: ssh.h:1058
@ SSH_OPERATION_MODE_SERVER
Definition: ssh.h:902
@ SSH_OPERATION_MODE_CLIENT
Definition: ssh.h:901
#define sshAllocMem(size)
Definition: ssh.h:731
#define SSH_BUFFER_SIZE
Definition: ssh.h:875
#define SshConnection
Definition: ssh.h:883
#define SshContext
Definition: ssh.h:879
@ SSH_MSG_NEWKEYS
Definition: ssh.h:953
@ SSH_MSG_KEXINIT
Definition: ssh.h:952
bool_t sshIsDhKexAlgo(const char_t *kexAlgo)
Test if the specified algorithm is a Diffie-Hellman key exchange algorithm.
const char_t * sshSelectEncAlgo(SshContext *context, const SshNameList *peerAlgoList)
Encryption algorithm negotiation.
const char_t * sshSelectKexAlgo(SshConnection *connection, const SshNameList *peerAlgoList)
Key exchange algorithm negotiation.
bool_t sshIsDhGexKexAlgo(const char_t *kexAlgo)
Test if the specified algorithm is a DH GEX key exchange algorithm.
bool_t sshIsHybridKexAlgo(const char_t *kexAlgo)
Test if the specified algorithm is a PQ-hybrid key exchange algorithm.
error_t sshFormatCompressionAlgoList(SshContext *context, uint8_t *p, size_t *written)
Format the list of compression algorithms.
error_t sshFormatEncAlgoList(SshContext *context, uint8_t *p, size_t *written)
Format the list of encryption algorithms.
bool_t sshIsGuessCorrect(SshContext *context, const SshNameList *kexAlgoList, const SshNameList *hostKeyAlgoList)
Check whether the other party's guess is correct.
const char_t * sshSelectMacAlgo(SshContext *context, const char_t *encAlgo, const SshNameList *peerAlgoList)
Integrity algorithm negotiation.
bool_t sshIsRsaKexAlgo(const char_t *kexAlgo)
Test if the specified algorithm is an RSA key exchange algorithm.
const char_t * sshSelectCompressionAlgo(SshContext *context, const SshNameList *peerAlgoList)
Compression algorithm negotiation.
const char_t * sshSelectHostKeyAlgo(SshContext *context, const SshNameList *peerAlgoList)
Host key algorithm negotiation.
error_t sshFormatMacAlgoList(SshContext *context, uint8_t *p, size_t *written)
Format the list of integrity algorithms.
bool_t sshIsEcdhKexAlgo(const char_t *kexAlgo)
Test if the specified algorithm is an ECDH key exchange algorithm.
error_t sshFormatHostKeyAlgoList(SshContext *context, uint8_t *p, size_t *written)
Format the list of host key algorithms.
error_t sshFormatKexAlgoList(SshConnection *connection, uint8_t *p, size_t *written)
Format the list of key exchange algorithms.
SSH algorithm negotiation.
error_t sshInitExchangeHash(SshConnection *connection)
Initialize exchange hash.
error_t sshUpdateExchangeHash(SshConnection *connection, const void *data, size_t length)
Update exchange hash calculation.
Exchange hash calculation.
error_t sshParseNewKeys(SshConnection *connection, const uint8_t *message, size_t length)
Parse SSH_MSG_NEWKEYS message.
Definition: ssh_kex.c:995
error_t sshFormatNewKeys(SshConnection *connection, uint8_t *p, size_t *length)
Format SSH_MSG_NEWKEYS message.
Definition: ssh_kex.c:447
error_t sshSendNewKeys(SshConnection *connection)
Send SSH_MSG_NEWKEYS message.
Definition: ssh_kex.c:194
error_t sshDigestClientKexInit(SshConnection *connection)
Update exchange hash with client's SSH_MSG_KEXINIT message.
Definition: ssh_kex.c:1179
error_t sshParseKexInit(SshConnection *connection, const uint8_t *message, size_t length)
Parse SSH_MSG_KEXINIT message.
Definition: ssh_kex.c:469
error_t sshSendKexInit(SshConnection *connection)
Send SSH_MSG_KEXINIT message.
Definition: ssh_kex.c:59
error_t sshFormatKexInit(SshConnection *connection, uint8_t *p, size_t *length)
Format SSH_MSG_KEXINIT message.
Definition: ssh_kex.c:298
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
SSH key exchange.
error_t sshParseKexDhMessage(SshConnection *connection, uint8_t type, const uint8_t *message, size_t length)
Parse Diffie-Hellman specific messages.
Definition: ssh_kex_dh.c:574
Diffie-Hellman key exchange.
error_t sshParseKexDhGexMessage(SshConnection *connection, uint8_t type, const uint8_t *message, size_t length)
Parse Diffie-Hellman Group Exchange specific messages.
DH GEX (Diffie-Hellman Group Exchange) key exchange.
error_t sshParseKexEcdhMessage(SshConnection *connection, uint8_t type, const uint8_t *message, size_t length)
Parse ECDH specific messages.
Definition: ssh_kex_ecdh.c:576
ECDH key exchange.
error_t sshParseKexHybridMessage(SshConnection *connection, uint8_t type, const uint8_t *message, size_t length)
Parse PQ-hybrid specific messages.
Post-quantum hybrid key exchange.
error_t sshParseKexRsaMessage(SshConnection *connection, uint8_t type, const uint8_t *message, size_t length)
Parse Diffie-Hellman specific messages.
Definition: ssh_kex_rsa.c:680
RSA key exchange.
error_t sshInitEncryptionEngine(SshConnection *connection, SshEncryptionEngine *encryptionEngine, const char_t *encAlgo, const char_t *macAlgo, uint8_t x)
Initialize encryption engine.
void sshFreeEncryptionEngine(SshEncryptionEngine *encryptionEngine)
Release encryption engine.
Key material generation.
int_t sshSelectHostKey(SshContext *context, const char_t *hostKeyAlgo)
Select a host key that matches then specified algorithm.
Definition: ssh_misc.c:757
error_t sshParseNameList(const uint8_t *p, size_t length, SshNameList *nameList)
Parse a comma-separated list of names.
Definition: ssh_misc.c:1227
bool_t sshCompareAlgo(const char_t *name1, const char_t *name2)
Compare algorithm names.
Definition: ssh_misc.c:1653
error_t sshFormatHostKey(SshConnection *connection, uint8_t *p, size_t *written)
Format host key structure.
Definition: ssh_misc.c:863
SSH helper functions.
error_t sshSendPacket(SshConnection *connection, uint8_t *payload, size_t payloadLen)
Send SSH packet.
Definition: ssh_packet.c:57
SSH packet encryption/decryption.
#define SSH_PACKET_HEADER_SIZE
Definition: ssh_packet.h:38
bool_t SshBoolean
Boolean.
Definition: ssh_types.h:48
String containing a comma-separated list of names.
Definition: ssh_types.h:78
const char_t * value
Definition: ssh_types.h:79
size_t length
Definition: ssh_types.h:80
uint8_t length
Definition: tcp.h:368