ssh_kex_dh_gex.c
Go to the documentation of this file.
1 /**
2  * @file ssh_kex_dh_gex.c
3  * @brief DH GEX (Diffie-Hellman Group Exchange) 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_transport.h"
38 #include "ssh/ssh_kex.h"
39 #include "ssh/ssh_kex_dh_gex.h"
40 #include "ssh/ssh_packet.h"
41 #include "ssh/ssh_key_material.h"
42 #include "ssh/ssh_exchange_hash.h"
43 #include "ssh/ssh_key_verify.h"
44 #include "ssh/ssh_cert_verify.h"
45 #include "ssh/ssh_misc.h"
46 #include "pkix/pem_import.h"
47 #include "debug.h"
48 
49 //Check SSH stack configuration
50 #if (SSH_SUPPORT == ENABLED && SSH_DH_GEX_KEX_SUPPORT == ENABLED)
51 
52 
53 /**
54  * @brief Send SSH_MSG_KEX_DH_GEX_REQUEST message
55  * @param[in] connection Pointer to the SSH connection
56  * @return Error code
57  **/
58 
60 {
61 #if (SSH_CLIENT_SUPPORT == ENABLED)
62  error_t error;
63  size_t length;
64  uint8_t *message;
65 
66  //Point to the buffer where to format the message
67  message = connection->buffer + SSH_PACKET_HEADER_SIZE;
68 
69  //Format SSH_MSG_KEX_DH_GEX_REQUEST message
70  error = sshFormatKexDhGexRequest(connection, message, &length);
71 
72  //Check status code
73  if(!error)
74  {
75  //Debug message
76  TRACE_INFO("Sending SSH_MSG_KEX_DH_GEX_REQUEST message (%" PRIuSIZE " bytes)...\r\n", length);
78 
79  //Send message
80  error = sshSendPacket(connection, message, length);
81  }
82 
83  //Check status code
84  if(!error)
85  {
86  //The server responds with an SSH_MSG_KEX_DH_GEX_GROUP message
87  connection->state = SSH_CONN_STATE_KEX_DH_GEX_GROUP;
88  }
89 
90  //Return status code
91  return error;
92 #else
93  //Client operation mode is not implemented
94  return ERROR_NOT_IMPLEMENTED;
95 #endif
96 }
97 
98 
99 /**
100  * @brief Send SSH_MSG_KEX_DH_GEX_GROUP message
101  * @param[in] connection Pointer to the SSH connection
102  * @return Error code
103  **/
104 
106 {
107 #if (SSH_SERVER_SUPPORT == ENABLED)
108  error_t error;
109  size_t length;
110  uint8_t *message;
111  SshContext *context;
112  SshDhGexGroup *dhGexGroup;
113 
114  //Point to the SSH context
115  context = connection->context;
116 
117  //Point to the buffer where to format the message
118  message = connection->buffer + SSH_PACKET_HEADER_SIZE;
119 
120  //Valid Diffie-Hellman group?
121  if(connection->dhGexGroupIndex >= 0)
122  {
123  //Point to the selected group
124  dhGexGroup = &context->dhGexGroups[connection->dhGexGroupIndex];
125 
126  //Decode the PEM structure that holds Diffie-Hellman parameters
127  error = pemImportDhParameters(dhGexGroup->dhParams,
128  dhGexGroup->dhParamsLen, &connection->dhContext.params);
129  }
130  else
131  {
132  //Report an error
133  error = ERROR_INVALID_GROUP;
134  }
135 
136  //Check status code
137  if(!error)
138  {
139  //Format SSH_MSG_KEX_DH_GEX_GROUP message
140  error = sshFormatKexDhGexGroup(connection, message, &length);
141  }
142 
143  //Check status code
144  if(!error)
145  {
146  //Debug message
147  TRACE_INFO("Sending SSH_MSG_KEX_DH_GEX_GROUP message (%" PRIuSIZE " bytes)...\r\n", length);
149 
150  //Send message
151  error = sshSendPacket(connection, message, length);
152  }
153 
154  //Check status code
155  if(!error)
156  {
157  //The client responds with an SSH_MSG_KEX_DH_GEX_INIT message
158  connection->state = SSH_CONN_STATE_KEX_DH_GEX_INIT;
159  }
160 
161  //Return status code
162  return error;
163 #else
164  //Server operation mode is not implemented
165  return ERROR_NOT_IMPLEMENTED;
166 #endif
167 }
168 
169 
170 /**
171  * @brief Send SSH_MSG_KEX_DH_GEX_INIT message
172  * @param[in] connection Pointer to the SSH connection
173  * @return Error code
174  **/
175 
177 {
178 #if (SSH_CLIENT_SUPPORT == ENABLED)
179  error_t error;
180  size_t length;
181  uint8_t *message;
182  SshContext *context;
183 
184  //Point to the SSH context
185  context = connection->context;
186 
187  //Point to the buffer where to format the message
188  message = connection->buffer + SSH_PACKET_HEADER_SIZE;
189 
190  //Generate an ephemeral key pair
191  error = dhGenerateKeyPair(&connection->dhContext, context->prngAlgo,
192  context->prngContext);
193 
194  //Check status code
195  if(!error)
196  {
197  //Format SSH_MSG_KEX_DH_GEX_INIT message
198  error = sshFormatKexDhGexInit(connection, message, &length);
199  }
200 
201  //Check status code
202  if(!error)
203  {
204  //Debug message
205  TRACE_INFO("Sending SSH_MSG_KEX_DH_GEX_INIT message (%" PRIuSIZE " bytes)...\r\n", length);
207 
208  //Send message
209  error = sshSendPacket(connection, message, length);
210  }
211 
212  //Check status code
213  if(!error)
214  {
215  //The server responds with an SSH_MSG_KEX_DH_GEX_REPLY message
216  connection->state = SSH_CONN_STATE_KEX_DH_GEX_REPLY;
217  }
218 
219  //Return status code
220  return error;
221 #else
222  //Client operation mode is not implemented
223  return ERROR_NOT_IMPLEMENTED;
224 #endif
225 }
226 
227 
228 /**
229  * @brief Send SSH_MSG_KEX_DH_GEX_REPLY message
230  * @param[in] connection Pointer to the SSH connection
231  * @return Error code
232  **/
233 
235 {
236 #if (SSH_SERVER_SUPPORT == ENABLED)
237  error_t error;
238  size_t length;
239  uint8_t *message;
240  SshContext *context;
241 
242  //Point to the SSH context
243  context = connection->context;
244 
245  //Point to the buffer where to format the message
246  message = connection->buffer + SSH_PACKET_HEADER_SIZE;
247 
248  //Generate an ephemeral key pair
249  error = dhGenerateKeyPair(&connection->dhContext, context->prngAlgo,
250  context->prngContext);
251 
252  //Check status code
253  if(!error)
254  {
255  //Format SSH_MSG_KEX_DH_GEX_REPLY message
256  error = sshFormatKexDhGexReply(connection, message, &length);
257  }
258 
259  //Check status code
260  if(!error)
261  {
262  //Debug message
263  TRACE_INFO("Sending SSH_MSG_KEX_DH_GEX_REPLY message (%" PRIuSIZE " bytes)...\r\n", length);
265 
266  //Send message
267  error = sshSendPacket(connection, message, length);
268  }
269 
270  //Check status code
271  if(!error)
272  {
273  //Key exchange ends by each side sending an SSH_MSG_NEWKEYS message
274  connection->state = SSH_CONN_STATE_SERVER_NEW_KEYS;
275  }
276 
277  //Return status code
278  return error;
279 #else
280  //Server operation mode is not implemented
281  return ERROR_NOT_IMPLEMENTED;
282 #endif
283 }
284 
285 
286 /**
287  * @brief Format SSH_MSG_KEX_DH_GEX_REQUEST message
288  * @param[in] connection Pointer to the SSH connection
289  * @param[out] p Buffer where to format the message
290  * @param[out] length Length of the resulting message, in bytes
291  * @return Error code
292  **/
293 
295  size_t *length)
296 {
297 #if (SSH_CLIENT_SUPPORT == ENABLED)
298  //Total length of the message
299  *length = 0;
300 
301  //Set message type
303 
304  //Point to the first field of the message
305  p += sizeof(uint8_t);
306  *length += sizeof(uint8_t);
307 
308  //Minimal size in bits of an acceptable group (min)
310  //Preferred size in bits of the group the server will send (n)
312  //Maximal size in bits of an acceptable group (max)
314 
315  //Total length of the packet
316  *length += 3 * sizeof(uint32_t);
317 
318  //Successful processing
319  return NO_ERROR;
320 #else
321  //Client operation mode is not implemented
322  return ERROR_NOT_IMPLEMENTED;
323 #endif
324 }
325 
326 
327 /**
328  * @brief Format SSH_MSG_KEX_DH_GEX_GROUP message
329  * @param[in] connection Pointer to the SSH connection
330  * @param[out] p Buffer where to format the message
331  * @param[out] length Length of the resulting message, in bytes
332  * @return Error code
333  **/
334 
336  size_t *length)
337 {
338 #if (SSH_SERVER_SUPPORT == ENABLED)
339  error_t error;
340  size_t n;
341 
342  //Total length of the message
343  *length = 0;
344 
345  //Set message type
347 
348  //Point to the first field of the message
349  p += sizeof(uint8_t);
350  *length += sizeof(uint8_t);
351 
352  //Format safe prime (p)
353  error = sshFormatMpint(&connection->dhContext.params.p, p, &n);
354  //Any error to report?
355  if(error)
356  return error;
357 
358  //Update exchange hash H with p (safe prime)
359  error = sshUpdateExchangeHashRaw(connection, p, n);
360  //Any error to report?
361  if(error)
362  return error;
363 
364  //Point to the next field
365  p += n;
366  *length += n;
367 
368  //Format generator (g)
369  error = sshFormatMpint(&connection->dhContext.params.g, p, &n);
370  //Any error to report?
371  if(error)
372  return error;
373 
374  //Update exchange hash H with g (generator for subgroup)
375  error = sshUpdateExchangeHashRaw(connection, p, n);
376  //Any error to report?
377  if(error)
378  return error;
379 
380  //Total length of the packet
381  *length += n;
382 
383  //Successful processing
384  return NO_ERROR;
385 #else
386  //Server operation mode is not implemented
387  return ERROR_NOT_IMPLEMENTED;
388 #endif
389 }
390 
391 
392 /**
393  * @brief Format SSH_MSG_KEX_DH_GEX_INIT message
394  * @param[in] connection Pointer to the SSH connection
395  * @param[out] p Buffer where to format the message
396  * @param[out] length Length of the resulting message, in bytes
397  * @return Error code
398  **/
399 
401  size_t *length)
402 {
403 #if (SSH_CLIENT_SUPPORT == ENABLED)
404  error_t error;
405  size_t n;
406 
407  //Total length of the message
408  *length = 0;
409 
410  //Set message type
412 
413  //Point to the first field of the message
414  p += sizeof(uint8_t);
415  *length += sizeof(uint8_t);
416 
417  //Format client's ephemeral public key
418  error = sshFormatMpint(&connection->dhContext.ya, p, &n);
419  //Any error to report?
420  if(error)
421  return error;
422 
423  //Total length of the message
424  *length += n;
425 
426  //Successful processing
427  return NO_ERROR;
428 #else
429  //Client operation mode is not implemented
430  return ERROR_NOT_IMPLEMENTED;
431 #endif
432 }
433 
434 
435 /**
436  * @brief Format SSH_MSG_KEX_DH_GEX_REPLY message
437  * @param[in] connection Pointer to the SSH connection
438  * @param[out] p Buffer where to format the message
439  * @param[out] length Length of the resulting message, in bytes
440  * @return Error code
441  **/
442 
444  size_t *length)
445 {
446 #if (SSH_SERVER_SUPPORT == ENABLED)
447  error_t error;
448  size_t n;
449 
450  //Total length of the message
451  *length = 0;
452 
453  //Set message type
455 
456  //Point to the first field of the message
457  p += sizeof(uint8_t);
458  *length += sizeof(uint8_t);
459 
460  //Format server's public host key (K_S)
461  error = sshFormatHostKey(connection, p + sizeof(uint32_t), &n);
462  //Any error to report?
463  if(error)
464  return error;
465 
466  //The octet string value is preceded by a uint32 containing its length
467  STORE32BE(n, p);
468 
469  //Point to the next field
470  p += sizeof(uint32_t) + n;
471  *length += sizeof(uint32_t) + n;
472 
473  //Format server's ephemeral public key (f)
474  error = sshFormatMpint(&connection->dhContext.ya, p, &n);
475  //Any error to report?
476  if(error)
477  return error;
478 
479  //Update exchange hash H with f (exchange value sent by the server)
480  error = sshUpdateExchangeHashRaw(connection, p, n);
481  //Any error to report?
482  if(error)
483  return error;
484 
485  //Point to the next field
486  p += n;
487  *length += n;
488 
489  //Compute the shared secret K
490  error = sshComputeDhGexSharedSecret(connection);
491  //Any error to report?
492  if(error)
493  return error;
494 
495  //Update exchange hash H with K (shared secret)
496  error = sshUpdateExchangeHashRaw(connection, connection->k,
497  connection->kLen);
498  //Any error to report?
499  if(error)
500  return error;
501 
502  //Compute the signature on the exchange hash
503  error = sshGenerateExchangeHashSignature(connection, p + sizeof(uint32_t),
504  &n);
505  //Any error to report?
506  if(error)
507  return error;
508 
509  //The octet string value is preceded by a uint32 containing its length
510  STORE32BE(n, p);
511 
512  //Total length of the message
513  *length += sizeof(uint32_t) + n;
514 
515  //The ephemeral private key shall be destroyed as soon as possible (refer
516  //to RFC 9212, section 6)
517  dhFree(&connection->dhContext);
518  dhInit(&connection->dhContext);
519 
520  //Successful processing
521  return NO_ERROR;
522 #else
523  //Server operation mode is not implemented
524  return ERROR_NOT_IMPLEMENTED;
525 #endif
526 }
527 
528 
529 /**
530  * @brief Parse SSH_MSG_KEX_DH_GEX_REQUEST message
531  * @param[in] connection Pointer to the SSH connection
532  * @param[in] message Pointer to message
533  * @param[in] length Length of the message, in bytes
534  * @return Error code
535  **/
536 
538  const uint8_t *message, size_t length)
539 {
540 #if (SSH_SERVER_SUPPORT == ENABLED)
541  error_t error;
542  const uint8_t *p;
543  uint32_t minDhModulusSize;
544  uint32_t preferredDhModulusSize;
545  uint32_t maxDhModulusSize;
546 
547  //Debug message
548  TRACE_INFO("SSH_MSG_KEX_DH_GEX_REQUEST message received (%" PRIuSIZE " bytes)...\r\n", length);
550 
551  //Check operation mode
552  if(connection->context->mode != SSH_OPERATION_MODE_SERVER)
554 
555  //Check connection state
556  if(connection->state != SSH_CONN_STATE_KEX_DH_GEX_REQUEST)
558 
559  //Sanity check
560  if(length < sizeof(uint8_t))
561  return ERROR_INVALID_MESSAGE;
562 
563  //Point to the first field of the message
564  p = message + sizeof(uint8_t);
565  //Remaining bytes to process
566  length -= sizeof(uint8_t);
567 
568  //Malformed message?
569  if(length != (3 * sizeof(uint32_t)))
570  return ERROR_INVALID_MESSAGE;
571 
572  //Minimal size in bits of an acceptable group
573  minDhModulusSize = LOAD32BE(p);
574  //Preferred size in bits of the group the server will send
575  preferredDhModulusSize = LOAD32BE(p + 4);
576  //Maximal size in bits of an acceptable group
577  maxDhModulusSize = LOAD32BE(p + 8);
578 
579  //Debug message
580  TRACE_DEBUG(" min = %" PRIu32 "\r\n", minDhModulusSize);
581  TRACE_DEBUG(" n = %" PRIu32 "\r\n", preferredDhModulusSize);
582  TRACE_DEBUG(" max = %" PRIu32 "\r\n", maxDhModulusSize);
583 
584  //The server finds a group that best matches the client's request (refer
585  //to RFC 4419, section 3)
586  connection->dhGexGroupIndex = sshSelectDhGexGroup(connection->context,
587  minDhModulusSize, preferredDhModulusSize, maxDhModulusSize);
588 
589  //No Diffie-Hellman group found?
590  if(connection->dhGexGroupIndex < 0)
591  return ERROR_INVALID_GROUP;
592 
593  //Update exchange hash H with min, n and max
594  error = sshUpdateExchangeHashRaw(connection, p, length);
595  //Any error to report?
596  if(error)
597  return error;
598 
599  //The server responds with an SSH_MSG_KEX_DH_GEX_GROUP message
600  return sshSendKexDhGexGroup(connection);
601 #else
602  //Server operation mode is not implemented
604 #endif
605 }
606 
607 
608 /**
609  * @brief Parse SSH_MSG_KEX_DH_GEX_REQUEST_OLD message
610  * @param[in] connection Pointer to the SSH connection
611  * @param[in] message Pointer to message
612  * @param[in] length Length of the message, in bytes
613  * @return Error code
614  **/
615 
617  const uint8_t *message, size_t length)
618 {
619 #if (SSH_SERVER_SUPPORT == ENABLED)
620  error_t error;
621  const uint8_t *p;
622  uint32_t preferredDhModulusSize;
623 
624  //Debug message
625  TRACE_INFO("SSH_MSG_KEX_DH_GEX_REQUEST_OLD message received (%" PRIuSIZE " bytes)...\r\n", length);
627 
628  //Check operation mode
629  if(connection->context->mode != SSH_OPERATION_MODE_SERVER)
631 
632  //Check connection state
633  if(connection->state != SSH_CONN_STATE_KEX_DH_GEX_REQUEST)
635 
636  //Sanity check
637  if(length < sizeof(uint8_t))
638  return ERROR_INVALID_MESSAGE;
639 
640  //Point to the first field of the message
641  p = message + sizeof(uint8_t);
642  //Remaining bytes to process
643  length -= sizeof(uint8_t);
644 
645  //Malformed message?
646  if(length != sizeof(uint32_t))
647  return ERROR_INVALID_MESSAGE;
648 
649  //SSH_MSG_KEX_DH_GEX_REQUEST_OLD is used for backward compatibility.
650  //Instead of sending min, n and max, the client only sends n (refer to
651  //RFC 4419, section 5)
652  preferredDhModulusSize = LOAD32BE(p);
653 
654  //Debug message
655  TRACE_DEBUG(" n = %" PRIu32 "\r\n", preferredDhModulusSize);
656 
657  //The server finds a group that best matches the client's request (refer
658  //to RFC 4419, section 3)
659  connection->dhGexGroupIndex = sshSelectDhGexGroup(connection->context,
660  SSH_MIN_DH_MODULUS_SIZE, preferredDhModulusSize, SSH_MAX_DH_MODULUS_SIZE);
661 
662  //No Diffie-Hellman group found?
663  if(connection->dhGexGroupIndex < 0)
664  return ERROR_INVALID_GROUP;
665 
666  //The hash is calculated using only n instead of min, n and max (refer to
667  //RFC 4419, section 5)
668  error = sshUpdateExchangeHashRaw(connection, p, length);
669  //Any error to report?
670  if(error)
671  return error;
672 
673  //The server responds with an SSH_MSG_KEX_DH_GEX_GROUP message
674  return sshSendKexDhGexGroup(connection);
675 #else
676  //Server operation mode is not implemented
678 #endif
679 }
680 
681 
682 /**
683  * @brief Parse SSH_MSG_KEX_DH_GEX_GROUP message
684  * @param[in] connection Pointer to the SSH connection
685  * @param[in] message Pointer to message
686  * @param[in] length Length of the message, in bytes
687  * @return Error code
688  **/
689 
691  size_t length)
692 {
693 #if (SSH_CLIENT_SUPPORT == ENABLED)
694  error_t error;
695  uint_t k;
696  const uint8_t *p;
697  SshBinaryString prime;
698  SshBinaryString generator;
699 
700  //Debug message
701  TRACE_INFO("SSH_MSG_KEX_DH_GEX_GROUP message received (%" PRIuSIZE " bytes)...\r\n", length);
703 
704  //Check operation mode
705  if(connection->context->mode != SSH_OPERATION_MODE_CLIENT)
707 
708  //Check connection state
709  if(connection->state != SSH_CONN_STATE_KEX_DH_GEX_GROUP)
711 
712  //Sanity check
713  if(length < sizeof(uint8_t))
714  return ERROR_INVALID_MESSAGE;
715 
716  //Point to the first field of the message
717  p = message + sizeof(uint8_t);
718  //Remaining bytes to process
719  length -= sizeof(uint8_t);
720 
721  //Decode safe prime (p)
722  error = sshParseBinaryString(p, length, &prime);
723  //Any error to report?
724  if(error)
725  return error;
726 
727  //Point to the next field
728  p += sizeof(uint32_t) + prime.length;
729  length -= sizeof(uint32_t) + prime.length;
730 
731  //Decode generator (g)
732  error = sshParseBinaryString(p, length, &generator);
733  //Any error to report?
734  if(error)
735  return error;
736 
737  //Point to the next field
738  p += sizeof(uint32_t) + generator.length;
739  length -= sizeof(uint32_t) + generator.length;
740 
741  //Malformed message?
742  if(length != 0)
743  return ERROR_INVALID_MESSAGE;
744 
745  //Convert the prime modulus to a multiple precision integer
746  error = mpiImport(&connection->dhContext.params.p, prime.value,
748  //Any error to report?
749  if(error)
750  return error;
751 
752  //Get the length of the prime modulus, in bits
753  k = mpiGetBitLength(&connection->dhContext.params.p);
754 
755  //Make sure the prime modulus is acceptable
756  if(k < SSH_MIN_DH_MODULUS_SIZE || k > SSH_MAX_DH_MODULUS_SIZE)
757  return ERROR_INVALID_GROUP;
758 
759  //Convert the generator to a multiple precision integer
760  error = mpiImport(&connection->dhContext.params.g, generator.value,
761  generator.length, MPI_FORMAT_BIG_ENDIAN);
762  //Any error to report?
763  if(error)
764  return error;
765 
766  //The client responds with an SSH_MSG_KEX_DH_GEX_INIT message
767  return sshSendKexDhGexInit(connection);
768 #else
769  //Client operation mode is not implemented
771 #endif
772 }
773 
774 
775 /**
776  * @brief Parse SSH_MSG_KEX_DH_GEX_INIT message
777  * @param[in] connection Pointer to the SSH connection
778  * @param[in] message Pointer to message
779  * @param[in] length Length of the message, in bytes
780  * @return Error code
781  **/
782 
783 error_t sshParseKexDhGexInit(SshConnection *connection, const uint8_t *message,
784  size_t length)
785 {
786 #if (SSH_SERVER_SUPPORT == ENABLED)
787  error_t error;
788  const uint8_t *p;
789  SshBinaryString publicKey;
790 
791  //Debug message
792  TRACE_INFO("SSH_MSG_KEX_DH_GEX_INIT message received (%" PRIuSIZE " bytes)...\r\n", length);
794 
795  //Check operation mode
796  if(connection->context->mode != SSH_OPERATION_MODE_SERVER)
798 
799  //Check connection state
800  if(connection->state != SSH_CONN_STATE_KEX_DH_GEX_INIT)
802 
803  //Sanity check
804  if(length < sizeof(uint8_t))
805  return ERROR_INVALID_MESSAGE;
806 
807  //Point to the first field of the message
808  p = message + sizeof(uint8_t);
809  //Remaining bytes to process
810  length -= sizeof(uint8_t);
811 
812  //Decode client's ephemeral public key (e)
813  error = sshParseBinaryString(p, length, &publicKey);
814  //Any error to report?
815  if(error)
816  return error;
817 
818  //Point to the next field
819  p += sizeof(uint32_t) + publicKey.length;
820  length -= sizeof(uint32_t) + publicKey.length;
821 
822  //Malformed message?
823  if(length != 0)
824  return ERROR_INVALID_MESSAGE;
825 
826  //Update exchange hash H with e (exchange value sent by the client)
827  error = sshUpdateExchangeHash(connection, publicKey.value,
828  publicKey.length);
829  //Any error to report?
830  if(error)
831  return error;
832 
833  //Load client's ephemeral public key
834  error = mpiImport(&connection->dhContext.yb, publicKey.value,
835  publicKey.length, MPI_FORMAT_BIG_ENDIAN);
836  //Any error to report?
837  if(error)
838  return error;
839 
840  //Ensure the public key is acceptable
841  error = dhCheckPublicKey(&connection->dhContext.params,
842  &connection->dhContext.yb);
843  //Any error to report?
844  if(error)
845  return error;
846 
847  //The server responds with an SSH_MSG_KEX_DH_GEX_REPLY message
848  return sshSendKexDhGexReply(connection);
849 #else
850  //Server operation mode is not implemented
852 #endif
853 }
854 
855 
856 /**
857  * @brief Parse SSH_MSG_KEX_DH_GEX_REPLY message
858  * @param[in] connection Pointer to the SSH connection
859  * @param[in] message Pointer to message
860  * @param[in] length Length of the message, in bytes
861  * @return Error code
862  **/
863 
865  size_t length)
866 {
867 #if (SSH_CLIENT_SUPPORT == ENABLED)
868  error_t error;
869  const uint8_t *p;
870  SshString hostKeyAlgo;
871  SshBinaryString hostKey;
872  SshBinaryString publicKey;
873  SshBinaryString signature;
874 
875  //Debug message
876  TRACE_INFO("SSH_MSG_KEX_DH_GEX_REPLY message received (%" PRIuSIZE " bytes)...\r\n", length);
878 
879  //Check operation mode
880  if(connection->context->mode != SSH_OPERATION_MODE_CLIENT)
882 
883  //Check connection state
884  if(connection->state != SSH_CONN_STATE_KEX_DH_GEX_REPLY)
886 
887  //Sanity check
888  if(length < sizeof(uint8_t))
889  return ERROR_INVALID_MESSAGE;
890 
891  //Point to the first field of the message
892  p = message + sizeof(uint8_t);
893  //Remaining bytes to process
894  length -= sizeof(uint8_t);
895 
896  //Decode server's public host key (K_S)
897  error = sshParseBinaryString(p, length, &hostKey);
898  //Any error to report?
899  if(error)
900  return error;
901 
902  //Point to the next field
903  p += sizeof(uint32_t) + hostKey.length;
904  length -= sizeof(uint32_t) + hostKey.length;
905 
906  //Decode server's ephemeral public key (f)
907  error = sshParseBinaryString(p, length, &publicKey);
908  //Any error to report?
909  if(error)
910  return error;
911 
912  //Point to the next field
913  p += sizeof(uint32_t) + publicKey.length;
914  length -= sizeof(uint32_t) + publicKey.length;
915 
916  //Decode the signature field
917  error = sshParseBinaryString(p, length, &signature);
918  //Any error to report?
919  if(error)
920  return error;
921 
922  //Point to the next field
923  p += sizeof(uint32_t) + signature.length;
924  length -= sizeof(uint32_t) + signature.length;
925 
926  //Malformed message?
927  if(length != 0)
928  return ERROR_INVALID_MESSAGE;
929 
930  //Get the selected server's host key algorithm
931  hostKeyAlgo.value = connection->serverHostKeyAlgo;
932  hostKeyAlgo.length = osStrlen(connection->serverHostKeyAlgo);
933 
934 #if (SSH_CERT_SUPPORT == ENABLED)
935  //Certificate-based authentication?
936  if(sshIsCertPublicKeyAlgo(&hostKeyAlgo))
937  {
938  //Verify server's certificate
939  error = sshVerifyServerCertificate(connection, &hostKeyAlgo, &hostKey);
940  }
941  else
942 #endif
943  {
944  //Verify server's host key
945  error = sshVerifyServerHostKey(connection, &hostKeyAlgo, &hostKey);
946  }
947 
948  //If the client fails to verify the server's host key, it should disconnect
949  //from the server by sending an SSH_DISCONNECT_HOST_KEY_NOT_VERIFIABLE message
950  if(error)
951  return ERROR_INVALID_KEY;
952 
953  //Update exchange hash H with K_S (server's public host key)
954  error = sshUpdateExchangeHash(connection, hostKey.value, hostKey.length);
955  //Any error to report?
956  if(error)
957  return error;
958 
959  //Update exchange hash H with min, n, max, p, g and e
960  error = sshDigestDhGexParams(connection);
961  //Any error to report?
962  if(error)
963  return error;
964 
965  //Update exchange hash H with f (exchange value sent by the server)
966  error = sshUpdateExchangeHash(connection, publicKey.value, publicKey.length);
967  //Any error to report?
968  if(error)
969  return error;
970 
971  //Load server's ephemeral public key
972  error = mpiImport(&connection->dhContext.yb, publicKey.value,
973  publicKey.length, MPI_FORMAT_BIG_ENDIAN);
974  //Any error to report?
975  if(error)
976  return error;
977 
978  //Ensure the public key is acceptable
979  error = dhCheckPublicKey(&connection->dhContext.params,
980  &connection->dhContext.yb);
981  //Any error to report?
982  if(error)
983  return error;
984 
985  //Compute the shared secret K
986  error = sshComputeDhGexSharedSecret(connection);
987  //Any error to report?
988  if(error)
989  return error;
990 
991  //Update exchange hash H with K (shared secret)
992  error = sshUpdateExchangeHashRaw(connection, connection->k,
993  connection->kLen);
994  //Any error to report?
995  if(error)
996  return error;
997 
998  //Verify the signature on the exchange hash
999  error = sshVerifyExchangeHashSignature(connection, &hostKey, &signature);
1000  //Any error to report?
1001  if(error)
1002  return error;
1003 
1004  //The ephemeral private key shall be destroyed as soon as possible (refer
1005  //to RFC 9212, section 6)
1006  dhFree(&connection->dhContext);
1007  dhInit(&connection->dhContext);
1008 
1009  //Key exchange ends by each side sending an SSH_MSG_NEWKEYS message
1010  return sshSendNewKeys(connection);
1011 #else
1012  //Client operation mode is not implemented
1013  return ERROR_UNEXPECTED_MESSAGE;
1014 #endif
1015 }
1016 
1017 
1018 /**
1019  * @brief Parse Diffie-Hellman Group Exchange specific messages
1020  * @param[in] connection Pointer to the SSH connection
1021  * @param[in] type SSH message type
1022  * @param[in] message Pointer to message
1023  * @param[in] length Length of the message, in bytes
1024  * @return Error code
1025  **/
1026 
1028  const uint8_t *message, size_t length)
1029 {
1030  error_t error;
1031 
1032 #if (SSH_CLIENT_SUPPORT == ENABLED)
1033  //Client operation mode?
1034  if(connection->context->mode == SSH_OPERATION_MODE_CLIENT)
1035  {
1036  //Check message type
1038  {
1039  //Parse SSH_MSG_KEX_DH_GEX_GROUP message
1040  error = sshParseKexDhGexGroup(connection, message, length);
1041  }
1042  else if(type == SSH_MSG_KEX_DH_GEX_REPLY)
1043  {
1044  //Parse SSH_MSG_KEX_DH_GEX_REPLY message
1045  error = sshParseKexDhGexReply(connection, message, length);
1046  }
1047  else
1048  {
1049  //Unknown message type
1050  error = ERROR_INVALID_TYPE;
1051  }
1052  }
1053  else
1054 #endif
1055 #if (SSH_SERVER_SUPPORT == ENABLED)
1056  //Server operation mode?
1057  if(connection->context->mode == SSH_OPERATION_MODE_SERVER)
1058  {
1059  //Check message type
1061  {
1062  //Parse SSH_MSG_KEX_DH_GEX_REQUEST message
1063  error = sshParseKexDhGexRequest(connection, message, length);
1064  }
1066  {
1067  //Parse SSH_MSG_KEX_DH_GEX_REQUEST_OLD message
1068  error = sshParseKexDhGexRequestOld(connection, message, length);
1069  }
1070  else if(type == SSH_MSG_KEX_DH_GEX_INIT)
1071  {
1072  //Parse SSH_MSG_KEX_DH_GEX_INIT message
1073  error = sshParseKexDhGexInit(connection, message, length);
1074  }
1075  else
1076  {
1077  //Unknown message type
1078  error = ERROR_INVALID_TYPE;
1079  }
1080  }
1081  else
1082 #endif
1083  //Invalid operation mode?
1084  {
1085  //Report an error
1086  error = ERROR_INVALID_TYPE;
1087  }
1088 
1089  //Return status code
1090  return error;
1091 }
1092 
1093 
1094 /**
1095  * @brief Select a Diffie-Hellman group that best matches client's request
1096  * @param[in] context Pointer to the SSH context
1097  * @param[in] minDhModulusSize Minimum acceptable size for Diffie-Hellman prime modulus
1098  * @param[in] preferredDhModulusSize Preferred size for Diffie-Hellman prime modulus
1099  * @param[in] maxDhModulusSize Maximum acceptable size for Diffie-Hellman prime modulus
1100  * @return Index of the selected Diffie-Hellman group, if any
1101  **/
1102 
1103 int_t sshSelectDhGexGroup(SshContext *context, uint32_t minDhModulusSize,
1104  uint32_t preferredDhModulusSize, uint32_t maxDhModulusSize)
1105 {
1106 #if (SSH_SERVER_SUPPORT == ENABLED)
1107  uint_t i;
1108  uint32_t a;
1109  uint32_t b;
1110  int_t bestIndex;
1111  const SshDhGexGroup *group;
1112  const SshDhGexGroup *bestGroup;
1113 
1114  //Initialize index
1115  bestIndex = -1;
1116  bestGroup = NULL;
1117 
1118  //Loop through the Diffie-Hellman groups
1119  for(i = 0; i < SSH_MAX_DH_GEX_GROUPS; i++)
1120  {
1121  //Point to the current group
1122  group = &context->dhGexGroups[i];
1123 
1124  //Valid prime modulus?
1125  if(group->dhModulusSize >= SSH_MIN_DH_MODULUS_SIZE &&
1127  {
1128  //Check whether the current group is acceptable
1129  if(group->dhModulusSize >= minDhModulusSize &&
1130  group->dhModulusSize <= maxDhModulusSize)
1131  {
1132  //Select the group that best matches client's request
1133  if(bestIndex < 0 || bestGroup == NULL)
1134  {
1135  bestIndex = i;
1136  bestGroup = group;
1137  }
1138  else
1139  {
1140  //The client indicates the preferred size
1141  if(group->dhModulusSize > preferredDhModulusSize)
1142  {
1143  a = group->dhModulusSize - preferredDhModulusSize;
1144  }
1145  else
1146  {
1147  a = preferredDhModulusSize - group->dhModulusSize;
1148  }
1149 
1150  if(bestGroup->dhModulusSize > preferredDhModulusSize)
1151  {
1152  b = bestGroup->dhModulusSize - preferredDhModulusSize;
1153  }
1154  else
1155  {
1156  b = preferredDhModulusSize - bestGroup->dhModulusSize;
1157  }
1158 
1159  if(a < b)
1160  {
1161  bestIndex = i;
1162  bestGroup = group;
1163  }
1164  }
1165  }
1166  }
1167  }
1168 
1169  //Return the index of the Diffie-Hellman group
1170  return bestIndex;
1171 #else
1172  //Server operation mode is not implemented
1173  return -1;
1174 #endif
1175 }
1176 
1177 
1178 /**
1179  * @brief Diffie-Hellman shared secret calculation
1180  * @param[in] connection Pointer to the SSH connection
1181  * @return Error code
1182  **/
1183 
1185 {
1186  error_t error;
1187 
1188  //Compute the shared secret K
1189  error = dhComputeSharedSecret(&connection->dhContext, connection->k,
1190  SSH_MAX_SHARED_SECRET_LEN - SSH_MAX_MPINT_OVERHEAD, &connection->kLen);
1191 
1192  //Check status code
1193  if(!error)
1194  {
1195  //Log shared secret (for debugging purpose only)
1196  sshDumpKey(connection, "SHARED_SECRET", connection->k, connection->kLen);
1197 
1198  //Convert the shared secret K to mpint representation
1199  error = sshConvertArrayToMpint(connection->k, connection->kLen,
1200  connection->k, &connection->kLen);
1201  }
1202 
1203  //Return status code
1204  return error;
1205 }
1206 
1207 
1208 /**
1209  * @brief Update exchange hash with min, n, max, p, g and e
1210  * @param[in] connection Pointer to the SSH connection
1211  * @return Error code
1212  **/
1213 
1215 {
1216  error_t error;
1217  size_t n;
1218  uint8_t *buffer;
1219 
1220  //Allocate a temporary buffer
1221  buffer = sshAllocMem(SSH_BUFFER_SIZE);
1222 
1223  //Successful memory allocation?
1224  if(buffer != NULL)
1225  {
1226  //Minimal size in bits of an acceptable group (min)
1228  //Preferred size in bits of the group the server will send (n)
1230  //Maximal size in bits of an acceptable group (max)
1231  STORE32BE(SSH_MAX_DH_MODULUS_SIZE, buffer + 8);
1232 
1233  //Update exchange hash H with min, n and max
1234  error = sshUpdateExchangeHashRaw(connection, buffer, 3 * sizeof(uint32_t));
1235 
1236  //Check status code
1237  if(!error)
1238  {
1239  //Format Diffie-Hellman prime modulus
1240  error = sshFormatMpint(&connection->dhContext.params.p, buffer, &n);
1241  }
1242 
1243  //Check status code
1244  if(!error)
1245  {
1246  //Update exchange hash H with p (safe prime)
1247  error = sshUpdateExchangeHashRaw(connection, buffer, n);
1248  }
1249 
1250  //Check status code
1251  if(!error)
1252  {
1253  //Format Diffie-Hellman generator
1254  error = sshFormatMpint(&connection->dhContext.params.g, buffer, &n);
1255  }
1256 
1257  //Check status code
1258  if(!error)
1259  {
1260  //Update exchange hash H with g (generator for subgroup)
1261  error = sshUpdateExchangeHashRaw(connection, buffer, n);
1262  }
1263 
1264  //Check status code
1265  if(!error)
1266  {
1267  //Format client's ephemeral public key
1268  error = sshFormatMpint(&connection->dhContext.ya, buffer, &n);
1269  }
1270 
1271  //Check status code
1272  if(!error)
1273  {
1274  //Update exchange hash H with e (exchange value sent by the client)
1275  error = sshUpdateExchangeHashRaw(connection, buffer, n);
1276  }
1277 
1278  //Release previously allocated memory
1279  sshFreeMem(buffer);
1280  }
1281  else
1282  {
1283  //Failed to allocate memory
1284  error = ERROR_OUT_OF_MEMORY;
1285  }
1286 
1287  //Return status code
1288  return error;
1289 }
1290 
1291 #endif
uint8_t message[]
Definition: chap.h:154
uint8_t type
Definition: coap_common.h:176
signed int int_t
Definition: compiler_port.h:49
unsigned int uint_t
Definition: compiler_port.h:50
#define PRIuSIZE
#define LOAD32BE(p)
Definition: cpu_endian.h:210
#define STORE32BE(a, p)
Definition: cpu_endian.h:286
Debugging facilities.
#define TRACE_DEBUG(...)
Definition: debug.h:107
#define TRACE_INFO(...)
Definition: debug.h:95
#define TRACE_VERBOSE_ARRAY(p, a, n)
Definition: debug.h:125
error_t dhGenerateKeyPair(DhContext *context, const PrngAlgo *prngAlgo, void *prngContext)
Diffie-Hellman key pair generation.
Definition: dh.c:119
void dhInit(DhContext *context)
Initialize Diffie-Hellman context.
Definition: dh.c:54
error_t dhComputeSharedSecret(DhContext *context, uint8_t *output, size_t outputSize, size_t *outputLen)
Compute Diffie-Hellman shared secret.
Definition: dh.c:223
error_t dhCheckPublicKey(DhParameters *params, const Mpi *publicKey)
Check Diffie-Hellman public value.
Definition: dh.c:183
void dhFree(DhContext *context)
Release Diffie-Hellman context.
Definition: dh.c:71
uint8_t n
error_t
Error codes.
Definition: error.h:43
@ ERROR_INVALID_TYPE
Definition: error.h:115
@ ERROR_INVALID_KEY
Definition: error.h:106
@ ERROR_INVALID_GROUP
Definition: error.h:274
@ ERROR_INVALID_MESSAGE
Definition: error.h:105
@ ERROR_NOT_IMPLEMENTED
Definition: error.h:66
@ NO_ERROR
Success.
Definition: error.h:44
@ ERROR_OUT_OF_MEMORY
Definition: error.h:63
@ ERROR_UNEXPECTED_MESSAGE
Definition: error.h:194
uint_t mpiGetBitLength(const Mpi *a)
Get the actual length in bits.
Definition: mpi.c:234
error_t mpiImport(Mpi *r, const uint8_t *data, uint_t length, MpiFormat format)
Octet string to integer conversion.
Definition: mpi.c:624
@ MPI_FORMAT_BIG_ENDIAN
Definition: mpi.h:71
uint8_t b
Definition: nbns_common.h:104
uint8_t p
Definition: ndp.h:300
uint8_t a
Definition: ndp.h:411
#define osStrlen(s)
Definition: os_port.h:165
error_t pemImportDhParameters(const char_t *input, size_t length, DhParameters *params)
Decode a PEM file containing Diffie-Hellman parameters.
Definition: pem_import.c:149
PEM file import functions.
Secure Shell (SSH)
#define sshFreeMem(p)
Definition: ssh.h:736
@ SSH_CONN_STATE_KEX_DH_GEX_REPLY
Definition: ssh.h:1055
@ SSH_CONN_STATE_KEX_DH_GEX_GROUP
Definition: ssh.h:1053
@ SSH_CONN_STATE_KEX_DH_GEX_REQUEST
Definition: ssh.h:1052
@ SSH_CONN_STATE_SERVER_NEW_KEYS
Definition: ssh.h:1061
@ SSH_CONN_STATE_KEX_DH_GEX_INIT
Definition: ssh.h:1054
@ 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 SSH_MAX_DH_GEX_GROUPS
Definition: ssh.h:675
#define SSH_MAX_SHARED_SECRET_LEN
Definition: ssh.h:851
#define SSH_MAX_MPINT_OVERHEAD
Definition: ssh.h:870
#define SshConnection
Definition: ssh.h:883
#define SshContext
Definition: ssh.h:879
#define SSH_PREFERRED_DH_MODULUS_SIZE
Definition: ssh.h:689
#define SSH_MAX_DH_MODULUS_SIZE
Definition: ssh.h:696
#define SSH_MIN_DH_MODULUS_SIZE
Definition: ssh.h:682
@ SSH_MSG_KEX_DH_GEX_REQUEST
Definition: ssh.h:962
@ SSH_MSG_KEX_DH_GEX_INIT
Definition: ssh.h:964
@ SSH_MSG_KEX_DH_GEX_GROUP
Definition: ssh.h:963
@ SSH_MSG_KEX_DH_GEX_REPLY
Definition: ssh.h:965
@ SSH_MSG_KEX_DH_GEX_REQUEST_OLD
Definition: ssh.h:961
bool_t sshIsCertPublicKeyAlgo(const SshString *publicKeyAlgo)
Test if the specified public key algorithm is using certificates.
SSH algorithm negotiation.
error_t sshVerifyServerCertificate(SshConnection *connection, const SshString *publicKeyAlgo, const SshBinaryString *hostKey)
Verify server's certificate.
SSH certificate verification.
error_t sshUpdateExchangeHash(SshConnection *connection, const void *data, size_t length)
Update exchange hash calculation.
error_t sshUpdateExchangeHashRaw(SshConnection *connection, const void *data, size_t length)
Update exchange hash calculation (raw data)
error_t sshGenerateExchangeHashSignature(SshConnection *connection, uint8_t *p, size_t *written)
Compute the signature on the exchange hash.
error_t sshVerifyExchangeHashSignature(SshConnection *connection, const SshBinaryString *serverHostKey, const SshBinaryString *signature)
Verify the signature on the exchange hash.
Exchange hash calculation.
error_t sshSendNewKeys(SshConnection *connection)
Send SSH_MSG_NEWKEYS message.
Definition: ssh_kex.c:194
SSH key exchange.
error_t sshFormatKexDhGexRequest(SshConnection *connection, uint8_t *p, size_t *length)
Format SSH_MSG_KEX_DH_GEX_REQUEST message.
error_t sshSendKexDhGexInit(SshConnection *connection)
Send SSH_MSG_KEX_DH_GEX_INIT message.
error_t sshParseKexDhGexReply(SshConnection *connection, const uint8_t *message, size_t length)
Parse SSH_MSG_KEX_DH_GEX_REPLY message.
error_t sshFormatKexDhGexReply(SshConnection *connection, uint8_t *p, size_t *length)
Format SSH_MSG_KEX_DH_GEX_REPLY message.
error_t sshParseKexDhGexRequestOld(SshConnection *connection, const uint8_t *message, size_t length)
Parse SSH_MSG_KEX_DH_GEX_REQUEST_OLD message.
error_t sshComputeDhGexSharedSecret(SshConnection *connection)
Diffie-Hellman shared secret calculation.
error_t sshSendKexDhGexReply(SshConnection *connection)
Send SSH_MSG_KEX_DH_GEX_REPLY message.
error_t sshParseKexDhGexRequest(SshConnection *connection, const uint8_t *message, size_t length)
Parse SSH_MSG_KEX_DH_GEX_REQUEST message.
int_t sshSelectDhGexGroup(SshContext *context, uint32_t minDhModulusSize, uint32_t preferredDhModulusSize, uint32_t maxDhModulusSize)
Select a Diffie-Hellman group that best matches client's request.
error_t sshFormatKexDhGexInit(SshConnection *connection, uint8_t *p, size_t *length)
Format SSH_MSG_KEX_DH_GEX_INIT message.
error_t sshParseKexDhGexGroup(SshConnection *connection, const uint8_t *message, size_t length)
Parse SSH_MSG_KEX_DH_GEX_GROUP message.
error_t sshDigestDhGexParams(SshConnection *connection)
Update exchange hash with min, n, max, p, g and e.
error_t sshParseKexDhGexMessage(SshConnection *connection, uint8_t type, const uint8_t *message, size_t length)
Parse Diffie-Hellman Group Exchange specific messages.
error_t sshSendKexDhGexRequest(SshConnection *connection)
Send SSH_MSG_KEX_DH_GEX_REQUEST message.
error_t sshFormatKexDhGexGroup(SshConnection *connection, uint8_t *p, size_t *length)
Format SSH_MSG_KEX_DH_GEX_GROUP message.
error_t sshSendKexDhGexGroup(SshConnection *connection)
Send SSH_MSG_KEX_DH_GEX_GROUP message.
error_t sshParseKexDhGexInit(SshConnection *connection, const uint8_t *message, size_t length)
Parse SSH_MSG_KEX_DH_GEX_INIT message.
DH GEX (Diffie-Hellman Group Exchange) key exchange.
void sshDumpKey(SshConnection *connection, const char_t *label, const uint8_t *key, size_t keyLen)
Dump secret key (for debugging purpose only)
Key material generation.
error_t sshVerifyServerHostKey(SshConnection *connection, const SshString *publicKeyAlgo, const SshBinaryString *hostKey)
Verify server's host key.
SSH host key verification.
error_t sshConvertArrayToMpint(const uint8_t *value, size_t length, uint8_t *p, size_t *written)
Convert a binary string to mpint representation.
Definition: ssh_misc.c:1531
error_t sshParseBinaryString(const uint8_t *p, size_t length, SshBinaryString *string)
Parse a binary string.
Definition: ssh_misc.c:1189
error_t sshFormatMpint(const Mpi *value, uint8_t *p, size_t *written)
Format a multiple precision integer.
Definition: ssh_misc.c:1487
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
SSH transport layer protocol.
Binary string.
Definition: ssh_types.h:67
const uint8_t * value
Definition: ssh_types.h:68
size_t length
Definition: ssh_types.h:69
Diffie-Hellman group.
Definition: ssh.h:1140
uint_t dhModulusSize
Length of the prime modulus, in bits.
Definition: ssh.h:1141
const char_t * dhParams
Diffie-Hellman parameters (PEM format)
Definition: ssh.h:1142
size_t dhParamsLen
Length of the Diffie-Hellman parameters.
Definition: ssh.h:1143
String.
Definition: ssh_types.h:56
const char_t * value
Definition: ssh_types.h:57
size_t length
Definition: ssh_types.h:58
uint8_t length
Definition: tcp.h:368