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