ssh_algorithms.c
Go to the documentation of this file.
1 /**
2  * @file ssh_algorithms.c
3  * @brief SSH algorithm negotiation
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_rsa.h"
38 #include "ssh/ssh_kex_dh_gex.h"
39 #include "ssh/ssh_misc.h"
40 #include "debug.h"
41 
42 //Check SSH stack configuration
43 #if (SSH_SUPPORT == ENABLED)
44 
45 
46 /**
47  * @brief List of supported key exchange algorithms
48  **/
49 
50 static const char_t *const sshSupportedKexAlgos[] =
51 {
52 #if (SSH_HYBRID_KEX_SUPPORT == ENABLED && SSH_SNTRUP761_SUPPORT == ENABLED && \
53  SSH_CURVE25519_SUPPORT == ENABLED && SSH_SHA512_SUPPORT == ENABLED)
54  "sntrup761x25519-sha512",
55  "sntrup761x25519-sha512@openssh.com",
56 #endif
57 #if (SSH_HYBRID_KEX_SUPPORT == ENABLED && SSH_MLKEM768_SUPPORT == ENABLED && \
58  SSH_CURVE25519_SUPPORT == ENABLED && SSH_SHA256_SUPPORT == ENABLED)
59  "mlkem768x25519-sha256",
60 #endif
61 #if (SSH_HYBRID_KEX_SUPPORT == ENABLED && SSH_MLKEM768_SUPPORT == ENABLED && \
62  SSH_NISTP256_SUPPORT == ENABLED && SSH_SHA256_SUPPORT == ENABLED)
63  "mlkem768nistp256-sha256",
64 #endif
65 #if (SSH_HYBRID_KEX_SUPPORT == ENABLED && SSH_MLKEM1024_SUPPORT == ENABLED && \
66  SSH_NISTP384_SUPPORT == ENABLED && SSH_SHA384_SUPPORT == ENABLED)
67  "mlkem1024nistp384-sha384",
68 #endif
69 #if (SSH_KEM_KEX_SUPPORT == ENABLED && SSH_MLKEM512_SUPPORT == ENABLED && \
70  SSH_SHA256_SUPPORT == ENABLED)
71  "mlkem512-sha256",
72 #endif
73 #if (SSH_KEM_KEX_SUPPORT == ENABLED && SSH_MLKEM768_SUPPORT == ENABLED && \
74  SSH_SHA256_SUPPORT == ENABLED)
75  "mlkem768-sha256",
76 #endif
77 #if (SSH_KEM_KEX_SUPPORT == ENABLED && SSH_MLKEM1024_SUPPORT == ENABLED && \
78  SSH_SHA384_SUPPORT == ENABLED)
79  "mlkem1024-sha384",
80 #endif
81 #if (SSH_ECDH_KEX_SUPPORT == ENABLED && SSH_CURVE25519_SUPPORT == ENABLED && \
82  SSH_SHA256_SUPPORT == ENABLED)
83  "curve25519-sha256",
84  "curve25519-sha256@libssh.org",
85 #endif
86 #if (SSH_ECDH_KEX_SUPPORT == ENABLED && SSH_CURVE448_SUPPORT == ENABLED && \
87  SSH_SHA512_SUPPORT == ENABLED)
88  "curve448-sha512",
89 #endif
90 #if (SSH_ECDH_KEX_SUPPORT == ENABLED && SSH_NISTP256_SUPPORT == ENABLED && \
91  SSH_SHA256_SUPPORT == ENABLED)
92  "ecdh-sha2-nistp256",
93 #endif
94 #if (SSH_ECDH_KEX_SUPPORT == ENABLED && SSH_NISTP384_SUPPORT == ENABLED && \
95  SSH_SHA384_SUPPORT == ENABLED)
96  "ecdh-sha2-nistp384",
97 #endif
98 #if (SSH_ECDH_KEX_SUPPORT == ENABLED && SSH_NISTP521_SUPPORT == ENABLED && \
99  SSH_SHA512_SUPPORT == ENABLED)
100  "ecdh-sha2-nistp521",
101 #endif
102 #if (SSH_DH_GEX_KEX_SUPPORT == ENABLED && SSH_SHA256_SUPPORT == ENABLED)
103  "diffie-hellman-group-exchange-sha256",
104 #endif
105 #if (SSH_DH_GEX_KEX_SUPPORT == ENABLED && SSH_SHA384_SUPPORT == ENABLED)
106  "diffie-hellman-group-exchange-sha384@ssh.com",
107 #endif
108 #if (SSH_DH_GEX_KEX_SUPPORT == ENABLED && SSH_SHA512_SUPPORT == ENABLED)
109  "diffie-hellman-group-exchange-sha512@ssh.com",
110 #endif
111 #if (SSH_DH_KEX_SUPPORT == ENABLED && SSH_SHA256_SUPPORT == ENABLED && \
112  SSH_MAX_DH_MODULUS_SIZE >= 2048 && SSH_MIN_DH_MODULUS_SIZE <= 2048)
113  "diffie-hellman-group14-sha256",
114 #endif
115 #if (SSH_DH_KEX_SUPPORT == ENABLED && SSH_SHA512_SUPPORT == ENABLED && \
116  SSH_MAX_DH_MODULUS_SIZE >= 3072 && SSH_MIN_DH_MODULUS_SIZE <= 3072)
117  "diffie-hellman-group15-sha512",
118 #endif
119 #if (SSH_DH_KEX_SUPPORT == ENABLED && SSH_SHA512_SUPPORT == ENABLED && \
120  SSH_MAX_DH_MODULUS_SIZE >= 4096 && SSH_MIN_DH_MODULUS_SIZE <= 4096)
121  "diffie-hellman-group16-sha512",
122 #endif
123 #if (SSH_DH_KEX_SUPPORT == ENABLED && SSH_SHA512_SUPPORT == ENABLED && \
124  SSH_MAX_DH_MODULUS_SIZE >= 6144 && SSH_MIN_DH_MODULUS_SIZE <= 6144)
125  "diffie-hellman-group17-sha512",
126 #endif
127 #if (SSH_DH_KEX_SUPPORT == ENABLED && SSH_SHA512_SUPPORT == ENABLED && \
128  SSH_MAX_DH_MODULUS_SIZE >= 8192 && SSH_MIN_DH_MODULUS_SIZE <= 8192)
129  "diffie-hellman-group18-sha512",
130 #endif
131 #if (SSH_RSA_KEX_SUPPORT == ENABLED && SSH_SHA256_SUPPORT == ENABLED && \
132  SSH_MAX_RSA_MODULUS_SIZE >= 2048)
133  "rsa2048-sha256",
134 #endif
135 #if (SSH_DH_GEX_KEX_SUPPORT == ENABLED && SSH_SHA224_SUPPORT == ENABLED)
136  "diffie-hellman-group-exchange-sha224@ssh.com",
137 #endif
138 #if (SSH_DH_GEX_KEX_SUPPORT == ENABLED && SSH_SHA1_SUPPORT == ENABLED)
139  "diffie-hellman-group-exchange-sha1",
140 #endif
141 #if (SSH_DH_KEX_SUPPORT == ENABLED && SSH_SHA1_SUPPORT == ENABLED && \
142  SSH_MAX_DH_MODULUS_SIZE >= 2048 && SSH_MIN_DH_MODULUS_SIZE <= 2048)
143  "diffie-hellman-group14-sha1",
144 #endif
145 #if (SSH_DH_KEX_SUPPORT == ENABLED && SSH_SHA1_SUPPORT == ENABLED && \
146  SSH_MAX_DH_MODULUS_SIZE >= 1024 && SSH_MIN_DH_MODULUS_SIZE <= 1024)
147  "diffie-hellman-group1-sha1",
148 #endif
149 #if (SSH_RSA_KEX_SUPPORT == ENABLED && SSH_SHA1_SUPPORT == ENABLED && \
150  SSH_MAX_RSA_MODULUS_SIZE >= 1024)
151  "rsa1024-sha1",
152 #endif
153 };
154 
155 
156 /**
157  * @brief List of supported host key algorithms
158  **/
159 
160 static const SshHostKeyAlgo sshSupportedHostKeyAlgos[] =
161 {
162 #if (SSH_ED25519_SIGN_SUPPORT == ENABLED && SSH_CERT_SUPPORT == ENABLED)
163  {
164  "ssh-ed25519-cert",
165  "ssh-ed25519-cert",
166  "ssh-ed25519"
167  },
168  {
169  "ssh-ed25519-cert-v01@openssh.com",
170  "ssh-ed25519-cert-v01@openssh.com",
171  "ssh-ed25519"
172  },
173 #endif
174 #if (SSH_ED25519_SIGN_SUPPORT == ENABLED)
175  {
176  "ssh-ed25519",
177  "ssh-ed25519",
178  "ssh-ed25519"
179  },
180 #endif
181 #if (SSH_ED448_SIGN_SUPPORT == ENABLED && SSH_CERT_SUPPORT == ENABLED)
182  {
183  "ssh-ed448-cert",
184  "ssh-ed448-cert",
185  "ssh-ed448"
186  },
187 #endif
188 #if (SSH_ED448_SIGN_SUPPORT == ENABLED)
189  {
190  "ssh-ed448",
191  "ssh-ed448",
192  "ssh-ed448"
193  },
194 #endif
195 #if (SSH_ECDSA_SIGN_SUPPORT == ENABLED && SSH_NISTP256_SUPPORT == ENABLED && \
196  SSH_SHA256_SUPPORT == ENABLED && SSH_CERT_SUPPORT == ENABLED)
197  {
198  "ecdsa-sha2-nistp256-cert",
199  "ecdsa-sha2-nistp256-cert",
200  "ecdsa-sha2-nistp256"
201  },
202  {
203  "ecdsa-sha2-nistp256-cert-v01@openssh.com",
204  "ecdsa-sha2-nistp256-cert-v01@openssh.com",
205  "ecdsa-sha2-nistp256"
206  },
207 #endif
208 #if (SSH_ECDSA_SIGN_SUPPORT == ENABLED && SSH_NISTP256_SUPPORT == ENABLED && \
209  SSH_SHA256_SUPPORT == ENABLED)
210  {
211  "ecdsa-sha2-nistp256",
212  "ecdsa-sha2-nistp256",
213  "ecdsa-sha2-nistp256"
214  },
215 #endif
216 #if (SSH_ECDSA_SIGN_SUPPORT == ENABLED && SSH_NISTP384_SUPPORT == ENABLED && \
217  SSH_SHA384_SUPPORT == ENABLED && SSH_CERT_SUPPORT == ENABLED)
218  {
219  "ecdsa-sha2-nistp384-cert",
220  "ecdsa-sha2-nistp384-cert",
221  "ecdsa-sha2-nistp384"
222  },
223  {
224  "ecdsa-sha2-nistp384-cert-v01@openssh.com",
225  "ecdsa-sha2-nistp384-cert-v01@openssh.com",
226  "ecdsa-sha2-nistp384"
227  },
228 #endif
229 #if (SSH_ECDSA_SIGN_SUPPORT == ENABLED && SSH_NISTP384_SUPPORT == ENABLED && \
230  SSH_SHA384_SUPPORT == ENABLED)
231  {
232  "ecdsa-sha2-nistp384",
233  "ecdsa-sha2-nistp384",
234  "ecdsa-sha2-nistp384"
235  },
236 #endif
237 #if (SSH_ECDSA_SIGN_SUPPORT == ENABLED && SSH_NISTP521_SUPPORT == ENABLED && \
238  SSH_SHA512_SUPPORT == ENABLED && SSH_CERT_SUPPORT == ENABLED)
239  {
240  "ecdsa-sha2-nistp521-cert",
241  "ecdsa-sha2-nistp521-cert",
242  "ecdsa-sha2-nistp521"
243  },
244  {
245  "ecdsa-sha2-nistp521-cert-v01@openssh.com",
246  "ecdsa-sha2-nistp521-cert-v01@openssh.com",
247  "ecdsa-sha2-nistp521"
248  },
249 #endif
250 #if (SSH_ECDSA_SIGN_SUPPORT == ENABLED && SSH_NISTP521_SUPPORT == ENABLED && \
251  SSH_SHA512_SUPPORT == ENABLED)
252  {
253  "ecdsa-sha2-nistp521",
254  "ecdsa-sha2-nistp521",
255  "ecdsa-sha2-nistp521"
256  },
257 #endif
258 #if (SSH_RSA_SIGN_SUPPORT == ENABLED && SSH_SHA256_SUPPORT == ENABLED && \
259  SSH_CERT_SUPPORT == ENABLED)
260  {
261  "rsa-sha2-256-cert",
262  "ssh-rsa-cert",
263  "rsa-sha2-256"
264  },
265  {
266  "rsa-sha2-256-cert-v01@openssh.com",
267  "ssh-rsa-cert-v01@openssh.com",
268  "rsa-sha2-256"
269  },
270 #endif
271 #if (SSH_RSA_SIGN_SUPPORT == ENABLED && SSH_SHA256_SUPPORT == ENABLED)
272  {
273  "rsa-sha2-256",
274  "ssh-rsa",
275  "rsa-sha2-256"
276  },
277 #endif
278 #if (SSH_RSA_SIGN_SUPPORT == ENABLED && SSH_SHA512_SUPPORT == ENABLED && \
279  SSH_CERT_SUPPORT == ENABLED)
280  {
281  "rsa-sha2-512-cert",
282  "ssh-rsa-cert",
283  "rsa-sha2-512"
284  },
285  {
286  "rsa-sha2-512-cert-v01@openssh.com",
287  "ssh-rsa-cert-v01@openssh.com",
288  "rsa-sha2-512"
289  },
290 #endif
291 #if (SSH_RSA_SIGN_SUPPORT == ENABLED && SSH_SHA512_SUPPORT == ENABLED)
292  {
293  "rsa-sha2-512",
294  "ssh-rsa",
295  "rsa-sha2-512"
296  },
297 #endif
298 #if (SSH_RSA_SIGN_SUPPORT == ENABLED && SSH_SHA1_SUPPORT == ENABLED && \
299  SSH_CERT_SUPPORT == ENABLED)
300  {
301  "ssh-rsa-cert",
302  "ssh-rsa-cert",
303  "ssh-rsa"
304  },
305  {
306  "ssh-rsa-cert-v01@openssh.com",
307  "ssh-rsa-cert-v01@openssh.com",
308  "ssh-rsa"
309  },
310 #endif
311 #if (SSH_RSA_SIGN_SUPPORT == ENABLED && SSH_SHA1_SUPPORT == ENABLED)
312  {
313  "ssh-rsa",
314  "ssh-rsa",
315  "ssh-rsa"
316  },
317 #endif
318 #if (SSH_DSA_SIGN_SUPPORT == ENABLED && SSH_SHA1_SUPPORT == ENABLED && \
319  SSH_CERT_SUPPORT == ENABLED)
320  {
321  "ssh-dss-cert",
322  "ssh-dss-cert",
323  "ssh-dss"
324  },
325  {
326  "ssh-dss-cert-v01@openssh.com",
327  "ssh-dss-cert-v01@openssh.com",
328  "ssh-dss"
329  },
330 #endif
331 #if (SSH_DSA_SIGN_SUPPORT == ENABLED && SSH_SHA1_SUPPORT == ENABLED)
332  {
333  "ssh-dss",
334  "ssh-dss",
335  "ssh-dss"
336  },
337 #endif
338 };
339 
340 
341 /**
342  * @brief List of supported encryption algorithms
343  **/
344 
345 static const char_t *const sshSupportedEncAlgos[] =
346 {
347 #if (SSH_CHACHA20_POLY1305_SUPPORT == ENABLED)
348  "chacha20-poly1305",
349  "chacha20-poly1305@openssh.com",
350 #endif
351 #if (SSH_AES_128_SUPPORT == ENABLED && SSH_GCM_CIPHER_SUPPORT == ENABLED)
352  "aes128-gcm",
353  "aes128-gcm@openssh.com",
354 #endif
355 #if (SSH_AES_256_SUPPORT == ENABLED && SSH_GCM_CIPHER_SUPPORT == ENABLED)
356  "aes256-gcm",
357  "aes256-gcm@openssh.com",
358 #endif
359 #if (SSH_AES_128_SUPPORT == ENABLED && SSH_RFC5647_SUPPORT == ENABLED)
360  "AEAD_AES_128_GCM",
361 #endif
362 #if (SSH_AES_256_SUPPORT == ENABLED && SSH_RFC5647_SUPPORT == ENABLED)
363  "AEAD_AES_256_GCM",
364 #endif
365 #if (SSH_CAMELLIA_128_SUPPORT == ENABLED && SSH_RFC5647_SUPPORT == ENABLED)
366  "AEAD_CAMELLIA_128_GCM",
367 #endif
368 #if (SSH_CAMELLIA_256_SUPPORT == ENABLED && SSH_RFC5647_SUPPORT == ENABLED)
369  "AEAD_CAMELLIA_256_GCM",
370 #endif
371 #if (SSH_AES_128_SUPPORT == ENABLED && SSH_CTR_CIPHER_SUPPORT == ENABLED)
372  "aes128-ctr",
373 #endif
374 #if (SSH_AES_192_SUPPORT == ENABLED && SSH_CTR_CIPHER_SUPPORT == ENABLED)
375  "aes192-ctr",
376 #endif
377 #if (SSH_AES_256_SUPPORT == ENABLED && SSH_CTR_CIPHER_SUPPORT == ENABLED)
378  "aes256-ctr",
379 #endif
380 #if (SSH_TWOFISH_128_SUPPORT == ENABLED && SSH_CTR_CIPHER_SUPPORT == ENABLED)
381  "twofish128-ctr",
382 #endif
383 #if (SSH_TWOFISH_192_SUPPORT == ENABLED && SSH_CTR_CIPHER_SUPPORT == ENABLED)
384  "twofish192-ctr",
385 #endif
386 #if (SSH_TWOFISH_256_SUPPORT == ENABLED && SSH_CTR_CIPHER_SUPPORT == ENABLED)
387  "twofish256-ctr",
388 #endif
389 #if (SSH_SERPENT_128_SUPPORT == ENABLED && SSH_CTR_CIPHER_SUPPORT == ENABLED)
390  "serpent128-ctr",
391 #endif
392 #if (SSH_SERPENT_192_SUPPORT == ENABLED && SSH_CTR_CIPHER_SUPPORT == ENABLED)
393  "serpent192-ctr",
394 #endif
395 #if (SSH_SERPENT_256_SUPPORT == ENABLED && SSH_CTR_CIPHER_SUPPORT == ENABLED)
396  "serpent256-ctr",
397 #endif
398 #if (SSH_CAMELLIA_128_SUPPORT == ENABLED && SSH_CTR_CIPHER_SUPPORT == ENABLED)
399  "camellia128-ctr",
400 #endif
401 #if (SSH_CAMELLIA_192_SUPPORT == ENABLED && SSH_CTR_CIPHER_SUPPORT == ENABLED)
402  "camellia192-ctr",
403 #endif
404 #if (SSH_CAMELLIA_256_SUPPORT == ENABLED && SSH_CTR_CIPHER_SUPPORT == ENABLED)
405  "camellia256-ctr",
406 #endif
407 #if (SSH_AES_128_SUPPORT == ENABLED && SSH_CBC_CIPHER_SUPPORT == ENABLED)
408  "aes128-cbc",
409 #endif
410 #if (SSH_AES_192_SUPPORT == ENABLED && SSH_CBC_CIPHER_SUPPORT == ENABLED)
411  "aes192-cbc",
412 #endif
413 #if (SSH_AES_256_SUPPORT == ENABLED && SSH_CBC_CIPHER_SUPPORT == ENABLED)
414  "aes256-cbc",
415 #endif
416 #if (SSH_TWOFISH_128_SUPPORT == ENABLED && SSH_CBC_CIPHER_SUPPORT == ENABLED)
417  "twofish128-cbc",
418 #endif
419 #if (SSH_TWOFISH_192_SUPPORT == ENABLED && SSH_CBC_CIPHER_SUPPORT == ENABLED)
420  "twofish192-cbc",
421 #endif
422 #if (SSH_TWOFISH_256_SUPPORT == ENABLED && SSH_CBC_CIPHER_SUPPORT == ENABLED)
423  "twofish256-cbc",
424  "twofish-cbc",
425 #endif
426 #if (SSH_SERPENT_128_SUPPORT == ENABLED && SSH_CBC_CIPHER_SUPPORT == ENABLED)
427  "serpent128-cbc",
428 #endif
429 #if (SSH_SERPENT_192_SUPPORT == ENABLED && SSH_CBC_CIPHER_SUPPORT == ENABLED)
430  "serpent192-cbc",
431 #endif
432 #if (SSH_SERPENT_256_SUPPORT == ENABLED && SSH_CBC_CIPHER_SUPPORT == ENABLED)
433  "serpent256-cbc",
434 #endif
435 #if (SSH_CAMELLIA_128_SUPPORT == ENABLED && SSH_CBC_CIPHER_SUPPORT == ENABLED)
436  "camellia128-cbc",
437 #endif
438 #if (SSH_CAMELLIA_192_SUPPORT == ENABLED && SSH_CBC_CIPHER_SUPPORT == ENABLED)
439  "camellia192-cbc",
440 #endif
441 #if (SSH_CAMELLIA_256_SUPPORT == ENABLED && SSH_CBC_CIPHER_SUPPORT == ENABLED)
442  "camellia256-cbc",
443 #endif
444 #if (SSH_SEED_SUPPORT == ENABLED && SSH_CBC_CIPHER_SUPPORT == ENABLED)
445  "seed-cbc@ssh.com",
446 #endif
447 #if (SSH_3DES_SUPPORT == ENABLED && SSH_CTR_CIPHER_SUPPORT == ENABLED)
448  "3des-ctr",
449 #endif
450 #if (SSH_3DES_SUPPORT == ENABLED && SSH_CBC_CIPHER_SUPPORT == ENABLED)
451  "3des-cbc",
452 #endif
453 #if (SSH_BLOWFISH_SUPPORT == ENABLED && SSH_CTR_CIPHER_SUPPORT == ENABLED)
454  "blowfish-ctr",
455 #endif
456 #if (SSH_BLOWFISH_SUPPORT == ENABLED && SSH_CBC_CIPHER_SUPPORT == ENABLED)
457  "blowfish-cbc",
458 #endif
459 #if (SSH_IDEA_SUPPORT == ENABLED && SSH_CTR_CIPHER_SUPPORT == ENABLED)
460  "idea-ctr",
461 #endif
462 #if (SSH_IDEA_SUPPORT == ENABLED && SSH_CBC_CIPHER_SUPPORT == ENABLED)
463  "idea-cbc",
464 #endif
465 #if (SSH_CAST128_SUPPORT == ENABLED && SSH_CTR_CIPHER_SUPPORT == ENABLED)
466  "cast128-ctr",
467 #endif
468 #if (SSH_CAST128_SUPPORT == ENABLED && SSH_CBC_CIPHER_SUPPORT == ENABLED)
469  "cast128-cbc",
470 #endif
471 #if (SSH_RC4_256_SUPPORT == ENABLED && SSH_STREAM_CIPHER_SUPPORT == ENABLED)
472  "arcfour256",
473 #endif
474 #if (SSH_RC4_128_SUPPORT == ENABLED && SSH_STREAM_CIPHER_SUPPORT == ENABLED)
475  "arcfour128",
476 #endif
477 #if (SSH_RC4_SUPPORT == ENABLED && SSH_STREAM_CIPHER_SUPPORT == ENABLED)
478  "arcfour",
479 #endif
480 };
481 
482 
483 /**
484  * @brief List of supported MAC algorithms
485  **/
486 
487 static const char_t *const sshSupportedMacAlgos[] =
488 {
489 #if (SSH_HMAC_SUPPORT == ENABLED && SSH_SHA256_SUPPORT == ENABLED && \
490  SSH_ETM_SUPPORT == ENABLED)
491  "hmac-sha2-256-etm@openssh.com",
492 #endif
493 #if (SSH_HMAC_SUPPORT == ENABLED && SSH_SHA256_SUPPORT == ENABLED)
494  "hmac-sha2-256",
495 #endif
496 #if (SSH_HMAC_SUPPORT == ENABLED && SSH_SHA512_SUPPORT == ENABLED && \
497  SSH_ETM_SUPPORT == ENABLED)
498  "hmac-sha2-512-etm@openssh.com",
499 #endif
500 #if (SSH_HMAC_SUPPORT == ENABLED && SSH_SHA512_SUPPORT == ENABLED)
501  "hmac-sha2-512",
502 #endif
503 #if (SSH_HMAC_SUPPORT == ENABLED && SSH_SHA1_SUPPORT == ENABLED && \
504  SSH_ETM_SUPPORT == ENABLED)
505  "hmac-sha1-etm@openssh.com",
506 #endif
507 #if (SSH_HMAC_SUPPORT == ENABLED && SSH_SHA1_SUPPORT == ENABLED)
508  "hmac-sha1",
509 #endif
510 #if (SSH_HMAC_SUPPORT == ENABLED && SSH_RIPEMD160_SUPPORT == ENABLED && \
511  SSH_ETM_SUPPORT == ENABLED)
512  "hmac-ripemd160-etm@openssh.com",
513 #endif
514 #if (SSH_HMAC_SUPPORT == ENABLED && SSH_RIPEMD160_SUPPORT == ENABLED)
515  "hmac-ripemd160",
516  "hmac-ripemd160@openssh.com",
517 #endif
518 #if (SSH_HMAC_SUPPORT == ENABLED && SSH_MD5_SUPPORT == ENABLED && \
519  SSH_ETM_SUPPORT == ENABLED)
520  "hmac-md5-etm@openssh.com",
521 #endif
522 #if (SSH_HMAC_SUPPORT == ENABLED && SSH_MD5_SUPPORT == ENABLED)
523  "hmac-md5",
524 #endif
525 #if (SSH_HMAC_SUPPORT == ENABLED && SSH_SHA1_96_SUPPORT == ENABLED && \
526  SSH_ETM_SUPPORT == ENABLED)
527  "hmac-sha1-96-etm@openssh.com",
528 #endif
529 #if (SSH_HMAC_SUPPORT == ENABLED && SSH_SHA1_96_SUPPORT == ENABLED)
530  "hmac-sha1-96",
531 #endif
532 #if (SSH_HMAC_SUPPORT == ENABLED && SSH_MD5_96_SUPPORT == ENABLED && \
533  SSH_ETM_SUPPORT == ENABLED)
534  "hmac-md5-96-etm@openssh.com",
535 #endif
536 #if (SSH_HMAC_SUPPORT == ENABLED && SSH_MD5_96_SUPPORT == ENABLED)
537  "hmac-md5-96",
538 #endif
539 #if (SSH_AES_128_SUPPORT == ENABLED && SSH_RFC5647_SUPPORT == ENABLED)
540  "AEAD_AES_128_GCM",
541 #endif
542 #if (SSH_AES_256_SUPPORT == ENABLED && SSH_RFC5647_SUPPORT == ENABLED)
543  "AEAD_AES_256_GCM",
544 #endif
545 #if (SSH_CAMELLIA_128_SUPPORT == ENABLED && SSH_RFC5647_SUPPORT == ENABLED)
546  "AEAD_CAMELLIA_128_GCM",
547 #endif
548 #if (SSH_CAMELLIA_256_SUPPORT == ENABLED && SSH_RFC5647_SUPPORT == ENABLED)
549  "AEAD_CAMELLIA_256_GCM",
550 #endif
551  ""
552 };
553 
554 
555 /**
556  * @brief List of supported compression algorithms
557  **/
558 
559 static const char_t *const sshSupportedCompressionAlgos[] =
560 {
561  "none"
562 };
563 
564 
565 /**
566  * @brief Format the list of key exchange algorithms
567  * @param[in] connection Pointer to the SSH connection
568  * @param[out] p Output stream where to write the name-list
569  * @param[out] written Total number of bytes that have been written
570  * @return Error code
571  **/
572 
574  size_t *written)
575 {
576  uint_t i;
577  size_t n;
578  bool_t acceptable;
579 
580  //The algorithm name-list is represented as a uint32 containing its length
581  //followed by a comma-separated list of zero or more names
582  n = sizeof(uint32_t);
583 
584  //Loop through the list of key exchange algorithms
585  for(i = 0; i < arraysize(sshSupportedKexAlgos); i++)
586  {
587  //Initialize flag
588  acceptable = FALSE;
589 
590 #if (SSH_RSA_KEX_SUPPORT == ENABLED)
591  //RSA key exchange algorithm?
592  if(connection->context->mode == SSH_OPERATION_MODE_SERVER &&
593  sshIsRsaKexAlgo(sshSupportedKexAlgos[i]))
594  {
595  //RSA algorithms can only be negotiated at server-side if a valid
596  //transient RSA key has been loaded
597  if(sshSelectTransientRsaKey(connection->context,
598  sshSupportedKexAlgos[i]) >= 0)
599  {
600  acceptable = TRUE;
601  }
602  }
603  else
604 #endif
605 #if (SSH_DH_GEX_KEX_SUPPORT == ENABLED)
606  //DH GEX key exchange algorithm?
607  if(connection->context->mode == SSH_OPERATION_MODE_SERVER &&
608  sshIsDhGexKexAlgo(sshSupportedKexAlgos[i]))
609  {
610  //Diffie-Hellman Group Exchange algorithms can only be negotiated at
611  //server-side if a valid group has been loaded
612  if(sshSelectDhGexGroup(connection->context, SSH_MIN_DH_MODULUS_SIZE,
614  {
615  acceptable = TRUE;
616  }
617  }
618  else
619 #endif
620  //Diffie-Hellman or ECDH key exchange algorithm?
621  {
622  //The current key exchange algorithm is acceptable
623  acceptable = TRUE;
624  }
625 
626  //Acceptable key exchange algorithm?
627  if(acceptable)
628  {
629  //Names are separated by commas
630  if(n != sizeof(uint32_t))
631  {
632  p[n++] = ',';
633  }
634 
635  //A name must have a non-zero length and it must not contain a comma
636  osStrcpy((char_t *) p + n, sshSupportedKexAlgos[i]);
637 
638  //Update the length of the name list
639  n += osStrlen(sshSupportedKexAlgos[i]);
640  }
641  }
642 
643 #if (SSH_EXT_INFO_SUPPORT == ENABLED)
644  //Applications implementing the extension negotiation mechanism must add an
645  //indicator name to the field kex_algorithms in the SSH_MSG_KEXINIT message
646  //sent by the application in the first key exchange (refer to RFC 8308,
647  //section 2.1)
648  if(!connection->newKeysSent)
649  {
650  const char_t *indicatorName;
651 
652  //Names are separated by commas
653  if(n != sizeof(uint32_t))
654  {
655  p[n++] = ',';
656  }
657 
658  //The indicator names inserted by the client and server are different
659  //to ensure these names will not produce a match and therefore not
660  //affect the algorithm chosen in key exchange algorithm negotiation
661  if(connection->context->mode == SSH_OPERATION_MODE_CLIENT)
662  {
663  indicatorName = "ext-info-c";
664  }
665  else
666  {
667  indicatorName = "ext-info-s";
668  }
669 
670  //The indicator name may be added at any position in the name-list
671  osStrcpy((char_t *) p + n, indicatorName);
672 
673  //Update the length of the name list
674  n += osStrlen(indicatorName);
675  }
676 #endif
677 
678 #if (SSH_KEX_STRICT_SUPPORT == ENABLED)
679  //The strict key exchange extension is signaled by including a additional
680  //algorithm in the initial kex_algorithms field
681  if(!connection->newKeysSent)
682  {
683  const char_t *indicatorName;
684 
685  //Names are separated by commas
686  if(n != sizeof(uint32_t))
687  {
688  p[n++] = ',';
689  }
690 
691  //The indicator names inserted by the client and server are different
692  //to ensure these names will not produce a match and therefore not
693  //affect the algorithm chosen in key exchange algorithm negotiation
694  if(connection->context->mode == SSH_OPERATION_MODE_CLIENT)
695  {
696  indicatorName = "kex-strict-c-v00@openssh.com";
697  }
698  else
699  {
700  indicatorName = "kex-strict-s-v00@openssh.com";
701  }
702 
703  //The indicator name may be added at any position in the name-list
704  osStrcpy((char_t *) p + n, indicatorName);
705 
706  //Update the length of the name list
707  n += osStrlen(indicatorName);
708  }
709 #endif
710 
711  //The name list is preceded by a uint32 containing its length
712  STORE32BE(n - sizeof(uint32_t), p);
713 
714  //Total number of bytes that have been written
715  *written = n;
716 
717  //Successful processing
718  return NO_ERROR;
719 }
720 
721 
722 /**
723  * @brief Format the list of host key algorithms
724  * @param[in] context Pointer to the SSH context
725  * @param[out] p Output stream where to write the name-list
726  * @param[out] written Total number of bytes that have been written
727  * @return Error code
728  **/
729 
731  size_t *written)
732 {
733  uint_t i;
734  size_t n;
735  const SshHostKeyAlgo *entry;
736 
737  //A name-list is represented as a uint32 containing its length followed
738  //by a comma-separated list of zero or more names
739  n = sizeof(uint32_t);
740 
741  //Loop through the supported host key algorithms
742  for(i = 0; i < arraysize(sshSupportedHostKeyAlgos); i++)
743  {
744  //Point to the current entry
745  entry = &sshSupportedHostKeyAlgos[i];
746 
747  //The client lists the algorithms that it is willing to accept. The
748  //server lists the algorithms for which it has host keys (refer to
749  //RFC 4253, section 7.1)
750  if(context->mode == SSH_OPERATION_MODE_CLIENT ||
751  sshSelectHostKey(context, entry->publicKeyAlgo) >= 0)
752  {
753  //Algorithm names are separated by commas
754  if(n != sizeof(uint32_t))
755  {
756  p[n++] = ',';
757  }
758 
759  //A name must have a non-zero length and it must not contain a comma
760  osStrcpy((char_t *) p + n, entry->publicKeyAlgo);
761 
762  //Update the length of the name list
763  n += osStrlen(entry->publicKeyAlgo);
764  }
765  }
766 
767  //The name list is preceded by a uint32 containing its length
768  STORE32BE(n - sizeof(uint32_t), p);
769 
770  //Total number of bytes that have been written
771  *written = n;
772 
773  //Successful processing
774  return NO_ERROR;
775 }
776 
777 
778 /**
779  * @brief Format the list of encryption algorithms
780  * @param[in] context Pointer to the SSH context
781  * @param[out] p Output stream where to write the name-list
782  * @param[out] written Total number of bytes that have been written
783  * @return Error code
784  **/
785 
786 error_t sshFormatEncAlgoList(SshContext *context, uint8_t *p, size_t *written)
787 {
788  //The algorithm name-list must be a comma-separated list of algorithm names.
789  //Each supported algorithm must be listed in order of preference
790  return sshFormatNameList(sshSupportedEncAlgos,
791  arraysize(sshSupportedEncAlgos), p, written);
792 }
793 
794 
795 /**
796  * @brief Format the list of integrity algorithms
797  * @param[in] context Pointer to the SSH context
798  * @param[out] p Output stream where to write the name-list
799  * @param[out] written Total number of bytes that have been written
800  * @return Error code
801  **/
802 
803 error_t sshFormatMacAlgoList(SshContext *context, uint8_t *p, size_t *written)
804 {
805  //The algorithm name-list must be a comma-separated list of algorithm names.
806  //Each supported algorithm must be listed in order of preference
807  return sshFormatNameList(sshSupportedMacAlgos,
808  arraysize(sshSupportedMacAlgos) - 1, p, written);
809 }
810 
811 
812 /**
813  * @brief Format the list of compression algorithms
814  * @param[in] context Pointer to the SSH context
815  * @param[out] p Output stream where to write the name-list
816  * @param[out] written Total number of bytes that have been written
817  * @return Error code
818  **/
819 
821  size_t *written)
822 {
823  //The algorithm name-list must be a comma-separated list of algorithm names.
824  //Each supported algorithm must be listed in order of preference
825  return sshFormatNameList(sshSupportedCompressionAlgos,
826  arraysize(sshSupportedCompressionAlgos), p, written);
827 }
828 
829 
830 /**
831  * @brief Format the list of public key algorithms
832  * @param[in] context Pointer to the SSH context
833  * @param[out] p Output stream where to write the name-list
834  * @param[out] written Total number of bytes that have been written
835  * @return Error code
836  **/
837 
839  size_t *written)
840 {
841  uint_t i;
842  size_t n;
843  const SshHostKeyAlgo *entry;
844 
845  //A name-list is represented as a uint32 containing its length followed
846  //by a comma-separated list of zero or more names
847  n = sizeof(uint32_t);
848 
849  //Enumerate all public key algorithms that are supported
850  for(i = 0; i < arraysize(sshSupportedHostKeyAlgos); i++)
851  {
852  //Point to the current entry
853  entry = &sshSupportedHostKeyAlgos[i];
854 
855  //Algorithm names are separated by commas
856  if(n != sizeof(uint32_t))
857  {
858  p[n++] = ',';
859  }
860 
861  //A name must have a non-zero length and it must not contain a comma
862  osStrcpy((char_t *) p + n, entry->publicKeyAlgo);
863 
864  //Update the length of the name list
865  n += osStrlen(entry->publicKeyAlgo);
866  }
867 
868  //The name list is preceded by a uint32 containing its length
869  STORE32BE(n - sizeof(uint32_t), p);
870 
871  //Total number of bytes that have been written
872  *written = n;
873 
874  //Successful processing
875  return NO_ERROR;
876 }
877 
878 
879 /**
880  * @brief Generic algorithm negotiation
881  * @param[in] context Pointer to the SSH context
882  * @param[in] peerAlgoList List of algorithms supported by the peer
883  * @param[in] supportedAlgoList List of algorithms supported by the entity
884  * @param[in] supportedAlgoListLen Number of items in the name list
885  * @return Name of the selected algorithm, if any
886  **/
887 
888 const char_t *sshSelectAlgo(SshContext *context, const SshNameList *peerAlgoList,
889  const char_t *const *supportedAlgoList, uint_t supportedAlgoListLen)
890 {
891  uint_t i;
892  uint_t j;
893  SshString name;
894  const char_t *selectedAlgo;
895 
896  //Name of the chosen algorithm
897  selectedAlgo = NULL;
898 
899  //Check whether SSH operates as a client or a server
900  if(context->mode == SSH_OPERATION_MODE_CLIENT)
901  {
902  //Loop through the list of algorithms supported by the SSH client
903  for(i = 0; i < supportedAlgoListLen && selectedAlgo == NULL; i++)
904  {
905  //Loop through the list of algorithms offered by the SSH server
906  for(j = 0; selectedAlgo == NULL; j++)
907  {
908  //Algorithm names are separated by commas
909  if(sshGetName(peerAlgoList, j, &name))
910  {
911  //Compare algorithm names
912  if(sshCompareString(&name, supportedAlgoList[i]))
913  {
914  //The chosen algorithm must be the first algorithm on the
915  //client's name list that is also on the server's name list
916  selectedAlgo = supportedAlgoList[i];
917  }
918  }
919  else
920  {
921  //The end of the list was reached
922  break;
923  }
924  }
925  }
926  }
927  else
928  {
929  //Loop through the list of algorithms offered by the SSH client
930  for(j = 0; selectedAlgo == NULL; j++)
931  {
932  //Algorithm names are separated by commas
933  if(sshGetName(peerAlgoList, j, &name))
934  {
935  //Loop through the list of algorithms supported by the SSH server
936  for(i = 0; i < supportedAlgoListLen && selectedAlgo == NULL; i++)
937  {
938  //Compare algorithm names
939  if(sshCompareString(&name, supportedAlgoList[i]))
940  {
941  //The chosen algorithm must be the first algorithm on the
942  //client's name list that is also on the server's name list
943  selectedAlgo = supportedAlgoList[i];
944  }
945  }
946  }
947  else
948  {
949  //The end of the list was reached
950  break;
951  }
952  }
953  }
954 
955  //Return the name of the chosen algorithm, if any
956  return selectedAlgo;
957 }
958 
959 
960 /**
961  * @brief Key exchange algorithm negotiation
962  * @param[in] connection Pointer to the SSH connection
963  * @param[in] peerAlgoList List of algorithms supported by the peer
964  * @return Name of the selected algorithm, if any
965  **/
966 
968  const SshNameList *peerAlgoList)
969 {
970  uint_t i;
971  uint_t j;
972  SshString name;
973  const char_t *selectedAlgo;
974 
975  //Name of the chosen host key algorithm
976  selectedAlgo = NULL;
977 
978  //Check whether SSH operates as a client or a server
979  if(connection->context->mode == SSH_OPERATION_MODE_CLIENT)
980  {
981  //Loop through the list of algorithms supported by the SSH client
982  for(i = 0; i < arraysize(sshSupportedKexAlgos) &&
983  selectedAlgo == NULL; i++)
984  {
985  //Loop through the list of algorithms offered by the SSH server
986  for(j = 0; selectedAlgo == NULL; j++)
987  {
988  //Algorithm names are separated by commas
989  if(sshGetName(peerAlgoList, j, &name))
990  {
991  //Compare algorithm names
992  if(sshCompareString(&name, sshSupportedKexAlgos[i]))
993  {
994  //The chosen algorithm must be the first algorithm on the
995  //client's name list that is also on the server's name list
996  selectedAlgo = sshSupportedKexAlgos[i];
997  }
998  }
999  else
1000  {
1001  //The end of the list was reached
1002  break;
1003  }
1004  }
1005  }
1006  }
1007  else
1008  {
1009  //Loop through the list of algorithms offered by the SSH client
1010  for(j = 0; selectedAlgo == NULL; j++)
1011  {
1012  //Algorithm names are separated by commas
1013  if(sshGetName(peerAlgoList, j, &name))
1014  {
1015  //Loop through the list of algorithms supported by the SSH server
1016  for(i = 0; i < arraysize(sshSupportedKexAlgos) &&
1017  selectedAlgo == NULL; i++)
1018  {
1019  //Compare algorithm names
1020  if(sshCompareString(&name, sshSupportedKexAlgos[i]))
1021  {
1022 #if (SSH_RSA_KEX_SUPPORT == ENABLED)
1023  //RSA key exchange algorithm?
1024  if(sshIsRsaKexAlgo(sshSupportedKexAlgos[i]))
1025  {
1026  //RSA algorithms can only be negotiated at server-side if
1027  //a valid transient RSA key has been loaded
1028  if(sshSelectTransientRsaKey(connection->context,
1029  sshSupportedKexAlgos[i]) >= 0)
1030  {
1031  selectedAlgo = sshSupportedKexAlgos[i];
1032  }
1033  }
1034  else
1035 #endif
1036 #if (SSH_DH_GEX_KEX_SUPPORT == ENABLED)
1037  //DH GEX key exchange algorithm?
1038  if(sshIsDhGexKexAlgo(sshSupportedKexAlgos[i]))
1039  {
1040  //Diffie-Hellman Group Exchange algorithms can only be
1041  //negotiated at server-side if a valid group has been
1042  //loaded
1043  if(sshSelectDhGexGroup(connection->context,
1046  {
1047  selectedAlgo = sshSupportedKexAlgos[i];
1048  }
1049  }
1050  else
1051 #endif
1052  //Diffie-Hellman or ECDH key exchange algorithm?
1053  {
1054  //Select current host key algorithm
1055  selectedAlgo = sshSupportedKexAlgos[i];
1056  }
1057  }
1058  }
1059  }
1060  else
1061  {
1062  //The end of the list was reached
1063  break;
1064  }
1065  }
1066  }
1067 
1068 #if (SSH_EXT_INFO_SUPPORT == ENABLED)
1069  //Applications implementing the extension negotiation mechanism must add an
1070  //indicator name to the field kex_algorithms in the SSH_MSG_KEXINIT message
1071  //sent by the application in the first key exchange (refer to RFC 8308,
1072  //section 2.1)
1073  if(!connection->newKeysSent)
1074  {
1075  const char_t *indicatorName;
1076 
1077  //The indicator names inserted by the client and server are different
1078  //to ensure these names will not produce a match and therefore not
1079  //affect the algorithm chosen in key exchange algorithm negotiation
1080  if(connection->context->mode == SSH_OPERATION_MODE_CLIENT)
1081  {
1082  indicatorName = "ext-info-s";
1083  }
1084  else
1085  {
1086  indicatorName = "ext-info-c";
1087  }
1088 
1089  //The indicator name may be added at any position in the name-list
1090  if(sshFindName(peerAlgoList, indicatorName) >= 0)
1091  {
1092  connection->extInfoReceived = TRUE;
1093  }
1094  else
1095  {
1096  connection->extInfoReceived = FALSE;
1097  }
1098  }
1099 #endif
1100 
1101 #if (SSH_KEX_STRICT_SUPPORT == ENABLED)
1102  //The strict key exchange extension is signaled by including a additional
1103  //algorithm in the initial kex_algorithms field
1104  if(!connection->newKeysSent)
1105  {
1106  const char_t *indicatorName;
1107 
1108  //The indicator names inserted by the client and server are different
1109  //to ensure these names will not produce a match and therefore not
1110  //affect the algorithm chosen in key exchange algorithm negotiation
1111  if(connection->context->mode == SSH_OPERATION_MODE_CLIENT)
1112  {
1113  indicatorName = "kex-strict-s-v00@openssh.com";
1114  }
1115  else
1116  {
1117  indicatorName = "kex-strict-c-v00@openssh.com";
1118  }
1119 
1120  //The indicator name may be added at any position in the name-list
1121  if(sshFindName(peerAlgoList, indicatorName) >= 0)
1122  {
1123  connection->kexStrictReceived = TRUE;
1124  }
1125  else
1126  {
1127  connection->kexStrictReceived = FALSE;
1128  }
1129  }
1130 #endif
1131 
1132  //Return the name of the chosen host key algorithm, if any
1133  return selectedAlgo;
1134 }
1135 
1136 
1137 /**
1138  * @brief Host key algorithm negotiation
1139  * @param[in] context Pointer to the SSH context
1140  * @param[in] peerAlgoList List of algorithms supported by the peer
1141  * @return Name of the selected algorithm, if any
1142  **/
1143 
1145  const SshNameList *peerAlgoList)
1146 {
1147  uint_t i;
1148  uint_t j;
1149  SshString name;
1150  const char_t *selectedAlgo;
1151  const SshHostKeyAlgo *entry;
1152 
1153  //Name of the chosen host key algorithm
1154  selectedAlgo = NULL;
1155 
1156  //Check whether SSH operates as a client or a server
1157  if(context->mode == SSH_OPERATION_MODE_CLIENT)
1158  {
1159  //Loop through the list of algorithms supported by the SSH client
1160  for(i = 0; i < arraysize(sshSupportedHostKeyAlgos) &&
1161  selectedAlgo == NULL; i++)
1162  {
1163  //Point to the current entry
1164  entry = &sshSupportedHostKeyAlgos[i];
1165 
1166  //Loop through the list of algorithms offered by the SSH server
1167  for(j = 0; selectedAlgo == NULL; j++)
1168  {
1169  //Algorithm names are separated by commas
1170  if(sshGetName(peerAlgoList, j, &name))
1171  {
1172  //Compare algorithm names
1173  if(sshCompareString(&name, entry->publicKeyAlgo))
1174  {
1175  //The chosen algorithm must be the first algorithm on the
1176  //client's name list that is also on the server's name list
1177  selectedAlgo = entry->publicKeyAlgo;
1178  }
1179  }
1180  else
1181  {
1182  //The end of the list was reached
1183  break;
1184  }
1185  }
1186  }
1187  }
1188  else
1189  {
1190  //Loop through the list of algorithms offered by the SSH client
1191  for(j = 0; selectedAlgo == NULL; j++)
1192  {
1193  //Algorithm names are separated by commas
1194  if(sshGetName(peerAlgoList, j, &name))
1195  {
1196  //Loop through the list of algorithms supported by the SSH server
1197  for(i = 0; i < arraysize(sshSupportedHostKeyAlgos) &&
1198  selectedAlgo == NULL; i++)
1199  {
1200  //Point to the current entry
1201  entry = &sshSupportedHostKeyAlgos[i];
1202 
1203  //Compare algorithm names
1204  if(sshCompareString(&name, entry->publicKeyAlgo))
1205  {
1206  //The chosen algorithm must be the first algorithm on the
1207  //client's name list that is also on the server's name list
1208  if(sshSelectHostKey(context, entry->publicKeyAlgo) >= 0)
1209  {
1210  //Select current host key algorithm
1211  selectedAlgo = entry->publicKeyAlgo;
1212  }
1213  }
1214  }
1215  }
1216  else
1217  {
1218  //The end of the list was reached
1219  break;
1220  }
1221  }
1222  }
1223 
1224  //Return the name of the chosen host key algorithm, if any
1225  return selectedAlgo;
1226 }
1227 
1228 
1229 /**
1230  * @brief Encryption algorithm negotiation
1231  * @param[in] context Pointer to the SSH context
1232  * @param[in] peerAlgoList List of algorithms supported by the peer
1233  * @return Name of the selected algorithm, if any
1234  **/
1235 
1237  const SshNameList *peerAlgoList)
1238 {
1239  //The chosen encryption algorithm to each direction must be the first
1240  //algorithm on the client's name-list that is also on the server's name-list
1241  return sshSelectAlgo(context, peerAlgoList, sshSupportedEncAlgos,
1242  arraysize(sshSupportedEncAlgos));
1243 }
1244 
1245 
1246 /**
1247  * @brief Integrity algorithm negotiation
1248  * @param[in] context Pointer to the SSH context
1249  * @param[in] encAlgo Selected encryption algorithm
1250  * @param[in] peerAlgoList List of algorithms supported by the peer
1251  * @return Name of the selected algorithm, if any
1252  **/
1253 
1254 const char_t *sshSelectMacAlgo(SshContext *context, const char_t *encAlgo,
1255  const SshNameList *peerAlgoList)
1256 {
1257  const char_t *selectedAlgo;
1258 
1259 #if (SSH_GCM_CIPHER_SUPPORT == ENABLED || SSH_CHACHA20_POLY1305_SUPPORT == ENABLED)
1260  //AES-GCM or ChaCha20Poly1305 encryption algorithm?
1261  if(sshCompareAlgo(encAlgo, "aes128-gcm") ||
1262  sshCompareAlgo(encAlgo, "aes128-gcm@openssh.com") ||
1263  sshCompareAlgo(encAlgo, "aes256-gcm") ||
1264  sshCompareAlgo(encAlgo, "aes256-gcm@openssh.com") ||
1265  sshCompareAlgo(encAlgo, "chacha20-poly1305") ||
1266  sshCompareAlgo(encAlgo, "chacha20-poly1305@openssh.com"))
1267  {
1268  //AEAD algorithms offer both encryption and authentication
1269  selectedAlgo = sshSupportedMacAlgos[arraysize(sshSupportedMacAlgos) - 1];
1270  }
1271  else
1272 #endif
1273 #if (SSH_RFC5647_SUPPORT == ENABLED)
1274  //AES-GCM or Camellia-GCM encryption algorithm?
1275  if(sshCompareAlgo(encAlgo, "AEAD_AES_128_GCM") ||
1276  sshCompareAlgo(encAlgo, "AEAD_AES_256_GCM") ||
1277  sshCompareAlgo(encAlgo, "AEAD_CAMELLIA_128_GCM") ||
1278  sshCompareAlgo(encAlgo, "AEAD_CAMELLIA_256_GCM"))
1279  {
1280  //If AES-GCM is selected as the encryption algorithm, it must also be
1281  //selected as the MAC algorithm (refer to RFC 5647, section 5.1)
1282  selectedAlgo = encAlgo;
1283  }
1284  else
1285 #endif
1286  //Non-AEAD encryption algorithm?
1287  {
1288  //The chosen MAC algorithm to each direction must be the first algorithm
1289  //on the client's name-list that is also on the server's name-list
1290  selectedAlgo = sshSelectAlgo(context, peerAlgoList, sshSupportedMacAlgos,
1291  arraysize(sshSupportedMacAlgos) - 1);
1292  }
1293 
1294  //Return the name of the chosen algorithm, if any
1295  return selectedAlgo;
1296 }
1297 
1298 
1299 /**
1300  * @brief Compression algorithm negotiation
1301  * @param[in] context Pointer to the SSH context
1302  * @param[in] peerAlgoList List of algorithms supported by the peer
1303  * @return Name of the selected algorithm, if any
1304  **/
1305 
1307  const SshNameList *peerAlgoList)
1308 {
1309  //The chosen compression algorithm to each direction must be the first
1310  //algorithm on the client's name-list that is also on the server's name-list
1311  return sshSelectAlgo(context, peerAlgoList, sshSupportedCompressionAlgos,
1312  arraysize(sshSupportedCompressionAlgos));
1313 }
1314 
1315 
1316 /**
1317  * @brief Public key algorithm selection
1318  * @param[in] context Pointer to the SSH context
1319  * @param[in] keyFormatId Key format identifier
1320  * @param[in] peerAlgoList List of public key algorithms supported by the
1321  * peer (optional parameter)
1322  * @return Name of the selected algorithm, if any
1323  **/
1324 
1326  const char_t *keyFormatId, const SshNameList *peerAlgoList)
1327 {
1328  uint_t i;
1329  uint_t j;
1330  SshString name;
1331  const char_t *selectedAlgo;
1332  const SshHostKeyAlgo *entry;
1333 
1334  //Name of the chosen public key algorithm
1335  selectedAlgo = NULL;
1336 
1337  //Loop through the list of supported algorithms
1338  for(i = 0; i < arraysize(sshSupportedHostKeyAlgos) &&
1339  selectedAlgo == NULL; i++)
1340  {
1341  //Point to the current entry
1342  entry = &sshSupportedHostKeyAlgos[i];
1343 
1344  //Check key format identifier
1345  if(sshCompareAlgo(entry->keyFormatId, keyFormatId))
1346  {
1347  //The parameter is optional
1348  if(peerAlgoList != NULL)
1349  {
1350  //Loop through the list of algorithms supported by the peer
1351  for(j = 0; selectedAlgo == NULL; j++)
1352  {
1353  //Algorithm names are separated by commas
1354  if(sshGetName(peerAlgoList, j, &name))
1355  {
1356  //Compare algorithm names
1357  if(sshCompareString(&name, entry->publicKeyAlgo))
1358  {
1359  //Select current public key algorithm
1360  selectedAlgo = entry->publicKeyAlgo;
1361  }
1362  }
1363  else
1364  {
1365  //The end of the list was reached
1366  break;
1367  }
1368  }
1369  }
1370  else
1371  {
1372  //Select current public key algorithm
1373  selectedAlgo = entry->publicKeyAlgo;
1374  }
1375  }
1376  }
1377 
1378  //Return the name of the chosen public key algorithm, if any
1379  return selectedAlgo;
1380 }
1381 
1382 
1383 /**
1384  * @brief Get the key format identifier used by a given public key algorithm
1385  * @param[in] publicKeyAlgo Public key algorithm
1386  * @return Key format identifier
1387  **/
1388 
1389 const char_t *sshGetKeyFormatId(const SshString *publicKeyAlgo)
1390 {
1391  uint_t i;
1392  const char_t *keyFormatId;
1393  const SshHostKeyAlgo *entry;
1394 
1395  //Initialize key format identifier
1396  keyFormatId = NULL;
1397 
1398  //Loop through the list of supported algorithms
1399  for(i = 0; i < arraysize(sshSupportedHostKeyAlgos) &&
1400  keyFormatId == NULL; i++)
1401  {
1402  //Point to the current entry
1403  entry = &sshSupportedHostKeyAlgos[i];
1404 
1405  //Matching entry?
1406  if(sshCompareString(publicKeyAlgo, entry->publicKeyAlgo))
1407  {
1408  keyFormatId = entry->keyFormatId;
1409  }
1410  }
1411 
1412  //Return the matching key format identifier
1413  return keyFormatId;
1414 }
1415 
1416 
1417 /**
1418  * @brief Get the signature format identifier used by a given public key algorithm
1419  * @param[in] publicKeyAlgo Public key algorithm
1420  * @return Signature format identifier
1421  **/
1422 
1423 const char_t *sshGetSignFormatId(const SshString *publicKeyAlgo)
1424 {
1425  uint_t i;
1426  const char_t *signFormatId;
1427  const SshHostKeyAlgo *entry;
1428 
1429  //Initialize signature format identifier
1430  signFormatId = NULL;
1431 
1432  //Loop through the list of supported algorithms
1433  for(i = 0; i < arraysize(sshSupportedHostKeyAlgos) &&
1434  signFormatId == NULL; i++)
1435  {
1436  //Point to the current entry
1437  entry = &sshSupportedHostKeyAlgos[i];
1438 
1439  //Matching entry?
1440  if(sshCompareString(publicKeyAlgo, entry->publicKeyAlgo))
1441  {
1442  signFormatId = entry->signFormatId;
1443  }
1444  }
1445 
1446  //Return the matching signature format identifier
1447  return signFormatId;
1448 }
1449 
1450 
1451 /**
1452  * @brief Check whether the other party's guess is correct
1453  * @param[in] context Pointer to the SSH context
1454  * @param[in] kexAlgoList List of key exchange algorithms advertised by the
1455  * other party
1456  * @param[in] hostKeyAlgoList List of host key algorithms advertised by the
1457  * other party
1458  * @return TRUE if the guess is correct else FALSE
1459  **/
1460 
1461 bool_t sshIsGuessCorrect(SshContext *context, const SshNameList *kexAlgoList,
1462  const SshNameList *hostKeyAlgoList)
1463 {
1464  bool_t correct;
1465  SshString preferredKexAlgo;
1466  SshString preferredHostKeyAlgo;
1467 
1468  //The first key exchange algorithm of the list is the preferred algorithm
1469  correct = sshGetName(kexAlgoList, 0, &preferredKexAlgo);
1470 
1471  //Each name-list must contain at least one algorithm name
1472  if(correct)
1473  {
1474  //The first host key algorithm of the list is the preferred algorithm
1475  correct = sshGetName(hostKeyAlgoList, 0, &preferredHostKeyAlgo);
1476  }
1477 
1478  //Each name-list must contain at least one algorithm name
1479  if(correct)
1480  {
1481  //The guess is considered wrong if the key exchange algorithm or the
1482  //host key algorithm is guessed wrong (server and client have different
1483  //preferred algorithm)
1484  if(!sshCompareString(&preferredKexAlgo, sshSupportedKexAlgos[0]) ||
1485  !sshCompareString(&preferredHostKeyAlgo, sshSupportedHostKeyAlgos[0].publicKeyAlgo))
1486  {
1487  correct = FALSE;
1488  }
1489  }
1490 
1491  //Return TRUE if the guess is correct
1492  return correct;
1493 }
1494 
1495 
1496 /**
1497  * @brief Test if the specified algorithm is an RSA key exchange algorithm
1498  * @param[in] kexAlgo Key exchange algorithm name
1499  * @return TRUE if RSA key exchange algorithm, else FALSE
1500  **/
1501 
1503 {
1504  //RSA key exchange algorithm?
1505  if(sshCompareAlgo(kexAlgo, "rsa1024-sha1") ||
1506  sshCompareAlgo(kexAlgo, "rsa2048-sha256"))
1507  {
1508  return TRUE;
1509  }
1510  else
1511  {
1512  return FALSE;
1513  }
1514 }
1515 
1516 
1517 /**
1518  * @brief Test if the specified algorithm is a Diffie-Hellman key exchange algorithm
1519  * @param[in] kexAlgo Key exchange algorithm name
1520  * @return TRUE if Diffie-Hellman key exchange algorithm, else FALSE
1521  **/
1522 
1524 {
1525  //Diffie-Hellman key exchange algorithm?
1526  if(sshCompareAlgo(kexAlgo, "diffie-hellman-group1-sha1") ||
1527  sshCompareAlgo(kexAlgo, "diffie-hellman-group14-sha1") ||
1528  sshCompareAlgo(kexAlgo, "diffie-hellman-group14-sha256") ||
1529  sshCompareAlgo(kexAlgo, "diffie-hellman-group15-sha512") ||
1530  sshCompareAlgo(kexAlgo, "diffie-hellman-group16-sha512") ||
1531  sshCompareAlgo(kexAlgo, "diffie-hellman-group17-sha512") ||
1532  sshCompareAlgo(kexAlgo, "diffie-hellman-group18-sha512"))
1533  {
1534  return TRUE;
1535  }
1536  else
1537  {
1538  return FALSE;
1539  }
1540 }
1541 
1542 
1543 /**
1544  * @brief Test if the specified algorithm is a DH GEX key exchange algorithm
1545  * @param[in] kexAlgo Key exchange algorithm name
1546  * @return TRUE if DH GEX key exchange algorithm, else FALSE
1547  **/
1548 
1550 {
1551  //DH GEX key exchange algorithm?
1552  if(sshCompareAlgo(kexAlgo, "diffie-hellman-group-exchange-sha1") ||
1553  sshCompareAlgo(kexAlgo, "diffie-hellman-group-exchange-sha256") ||
1554  sshCompareAlgo(kexAlgo, "diffie-hellman-group-exchange-sha224@ssh.com") ||
1555  sshCompareAlgo(kexAlgo, "diffie-hellman-group-exchange-sha384@ssh.com") ||
1556  sshCompareAlgo(kexAlgo, "diffie-hellman-group-exchange-sha512@ssh.com"))
1557  {
1558  return TRUE;
1559  }
1560  else
1561  {
1562  return FALSE;
1563  }
1564 }
1565 
1566 
1567 /**
1568  * @brief Test if the specified algorithm is an ECDH key exchange algorithm
1569  * @param[in] kexAlgo Key exchange algorithm name
1570  * @return TRUE if ECDH key exchange algorithm, else FALSE
1571  **/
1572 
1574 {
1575  //ECDH key exchange algorithm?
1576  if(sshCompareAlgo(kexAlgo, "ecdh-sha2-nistp256") ||
1577  sshCompareAlgo(kexAlgo, "ecdh-sha2-nistp384") ||
1578  sshCompareAlgo(kexAlgo, "ecdh-sha2-nistp521") ||
1579  sshCompareAlgo(kexAlgo, "curve25519-sha256") ||
1580  sshCompareAlgo(kexAlgo, "curve25519-sha256@libssh.org") ||
1581  sshCompareAlgo(kexAlgo, "curve448-sha512"))
1582  {
1583  return TRUE;
1584  }
1585  else
1586  {
1587  return FALSE;
1588  }
1589 }
1590 
1591 
1592 /**
1593  * @brief Test if the specified algorithm is an ML-KEM key exchange algorithm
1594  * @param[in] kexAlgo Key exchange algorithm name
1595  * @return TRUE if ML-KEM key exchange algorithm, else FALSE
1596  **/
1597 
1599 {
1600  //ML-KEM key exchange algorithm?
1601  if(sshCompareAlgo(kexAlgo, "mlkem512-sha256") ||
1602  sshCompareAlgo(kexAlgo, "mlkem768-sha256") ||
1603  sshCompareAlgo(kexAlgo, "mlkem1024-sha384"))
1604  {
1605  return TRUE;
1606  }
1607  else
1608  {
1609  return FALSE;
1610  }
1611 }
1612 
1613 
1614 /**
1615  * @brief Test if the specified algorithm is a PQ-hybrid key exchange algorithm
1616  * @param[in] kexAlgo Key exchange algorithm name
1617  * @return TRUE if PQ-hybrid key exchange algorithm, else FALSE
1618  **/
1619 
1621 {
1622  //Post-quantum hybrid key exchange algorithm?
1623  if(sshCompareAlgo(kexAlgo, "mlkem768nistp256-sha256") ||
1624  sshCompareAlgo(kexAlgo, "mlkem1024nistp384-sha384") ||
1625  sshCompareAlgo(kexAlgo, "mlkem768x25519-sha256") ||
1626  sshCompareAlgo(kexAlgo, "sntrup761x25519-sha512") ||
1627  sshCompareAlgo(kexAlgo, "sntrup761x25519-sha512@openssh.com"))
1628  {
1629  return TRUE;
1630  }
1631  else
1632  {
1633  return FALSE;
1634  }
1635 }
1636 
1637 
1638 /**
1639  * @brief Test if the specified public key algorithm is using certificates
1640  * @param[in] publicKeyAlgo Public key algorithm name
1641  * @return TRUE if the public key algorithm is using certificates, else FALSE
1642  **/
1643 
1645 {
1646  //Check public key algorithm name
1647  if(sshCompareString(publicKeyAlgo, "ssh-rsa-cert") ||
1648  sshCompareString(publicKeyAlgo, "ssh-rsa-cert-v01@openssh.com") ||
1649  sshCompareString(publicKeyAlgo, "rsa-sha2-256-cert") ||
1650  sshCompareString(publicKeyAlgo, "rsa-sha2-256-cert-v01@openssh.com") ||
1651  sshCompareString(publicKeyAlgo, "rsa-sha2-512-cert") ||
1652  sshCompareString(publicKeyAlgo, "rsa-sha2-512-cert-v01@openssh.com") ||
1653  sshCompareString(publicKeyAlgo, "ssh-dss-cert") ||
1654  sshCompareString(publicKeyAlgo, "ssh-dss-cert-v01@openssh.com") ||
1655  sshCompareString(publicKeyAlgo, "ecdsa-sha2-nistp256-cert") ||
1656  sshCompareString(publicKeyAlgo, "ecdsa-sha2-nistp256-cert-v01@openssh.com") ||
1657  sshCompareString(publicKeyAlgo, "ecdsa-sha2-nistp384-cert") ||
1658  sshCompareString(publicKeyAlgo, "ecdsa-sha2-nistp384-cert-v01@openssh.com") ||
1659  sshCompareString(publicKeyAlgo, "ecdsa-sha2-nistp521-cert") ||
1660  sshCompareString(publicKeyAlgo, "ecdsa-sha2-nistp521-cert-v01@openssh.com") ||
1661  sshCompareString(publicKeyAlgo, "ssh-ed25519-cert") ||
1662  sshCompareString(publicKeyAlgo, "ssh-ed25519-cert-v01@openssh.com") ||
1663  sshCompareString(publicKeyAlgo, "ssh-ed448-cert"))
1664  {
1665  return TRUE;
1666  }
1667  else
1668  {
1669  return FALSE;
1670  }
1671 }
1672 
1673 
1674 /**
1675  * @brief Test if the specified public key algorithm is using X.509 certificates
1676  * @param[in] publicKeyAlgo Public key algorithm name
1677  * @return TRUE if the public key algorithm is using X.509 certificates, else FALSE
1678  **/
1679 
1681 {
1682  //Check public key algorithm name
1683  if(sshCompareString(publicKeyAlgo, "x509v3-ssh-dss") ||
1684  sshCompareString(publicKeyAlgo, "x509v3-ssh-rsa") ||
1685  sshCompareString(publicKeyAlgo, "x509v3-rsa2048-sha256") ||
1686  sshCompareString(publicKeyAlgo, "x509v3-ecdsa-sha2-nistp256") ||
1687  sshCompareString(publicKeyAlgo, "x509v3-ecdsa-sha2-nistp384") ||
1688  sshCompareString(publicKeyAlgo, "x509v3-ecdsa-sha2-nistp521"))
1689  {
1690  return TRUE;
1691  }
1692  else
1693  {
1694  return FALSE;
1695  }
1696 }
1697 
1698 #endif
const char_t * sshSelectEncAlgo(SshContext *context, const SshNameList *peerAlgoList)
Encryption algorithm negotiation.
int bool_t
Definition: compiler_port.h:63
bool_t sshIsKemKexAlgo(const char_t *kexAlgo)
Test if the specified algorithm is an ML-KEM key exchange algorithm.
const char_t * publicKeyAlgo
Public key algorithm.
Definition: ssh.h:1188
uint8_t p
Definition: ndp.h:300
#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.
bool_t sshGetName(const SshNameList *nameList, uint_t index, SshString *name)
Get the element at specified index.
Definition: ssh_misc.c:1364
char_t name[]
error_t sshFormatNameList(const char_t *const nameList[], uint_t nameListLen, uint8_t *p, size_t *written)
Format a comma-separated list of names.
Definition: ssh_misc.c:1473
#define osStrlen(s)
Definition: os_port.h:168
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.
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.
bool_t sshCompareString(const SshString *string, const char_t *value)
Compare a binary string against the supplied value.
Definition: ssh_misc.c:1691
const char_t * sshSelectPublicKeyAlgo(SshContext *context, const char_t *keyFormatId, const SshNameList *peerAlgoList)
Public key algorithm selection.
bool_t sshIsCertPublicKeyAlgo(const SshString *publicKeyAlgo)
Test if the specified public key algorithm is using certificates.
error_t sshFormatPublicKeyAlgoList(SshContext *context, uint8_t *p, size_t *written)
Format the list of public key algorithms.
#define FALSE
Definition: os_port.h:46
RSA key exchange.
const char_t * sshGetKeyFormatId(const SshString *publicKeyAlgo)
Get the key format identifier used by a given public key algorithm.
#define SshContext
Definition: ssh.h:892
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
String containing a comma-separated list of names.
Definition: ssh_types.h:78
@ SSH_OPERATION_MODE_SERVER
Definition: ssh.h:915
@ SSH_OPERATION_MODE_CLIENT
Definition: ssh.h:914
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.
Host key algorithm.
Definition: ssh.h:1187
String.
Definition: ssh_types.h:56
const char_t * sshSelectKexAlgo(SshConnection *connection, const SshNameList *peerAlgoList)
Key exchange algorithm negotiation.
const char_t * keyFormatId
Key format identifier.
Definition: ssh.h:1189
const char_t * sshSelectAlgo(SshContext *context, const SshNameList *peerAlgoList, const char_t *const *supportedAlgoList, uint_t supportedAlgoListLen)
Generic algorithm negotiation.
error_t sshFormatEncAlgoList(SshContext *context, uint8_t *p, size_t *written)
Format the list of encryption algorithms.
char char_t
Definition: compiler_port.h:55
uint8_t n
#define SshConnection
Definition: ssh.h:896
#define SSH_MAX_DH_MODULUS_SIZE
Definition: ssh.h:696
const char_t * sshSelectHostKeyAlgo(SshContext *context, const SshNameList *peerAlgoList)
Host key algorithm negotiation.
#define SSH_MIN_DH_MODULUS_SIZE
Definition: ssh.h:682
bool_t sshIsX509CertPublicKeyAlgo(const SshString *publicKeyAlgo)
Test if the specified public key algorithm is using X.509 certificates.
SSH helper functions.
int_t sshSelectHostKey(SshContext *context, const char_t *hostKeyAlgo)
Select a host key that matches then specified algorithm.
Definition: ssh_misc.c:769
int_t sshSelectTransientRsaKey(SshContext *context, const char_t *kexAlgo)
Select a transient RSA key.
Definition: ssh_kex_rsa.c:743
bool_t sshIsEcdhKexAlgo(const char_t *kexAlgo)
Test if the specified algorithm is an ECDH key exchange algorithm.
unsigned int uint_t
Definition: compiler_port.h:57
Secure Shell (SSH)
int_t sshFindName(const SshNameList *nameList, const char_t *name)
Search a name list for a given name.
Definition: ssh_misc.c:1313
SSH algorithm negotiation.
#define osStrcpy(s1, s2)
Definition: os_port.h:210
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 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.
const char_t * signFormatId
Signature format identifier.
Definition: ssh.h:1190
@ NO_ERROR
Success.
Definition: error.h:44
#define SSH_PREFERRED_DH_MODULUS_SIZE
Definition: ssh.h:689
Debugging facilities.
#define arraysize(a)
Definition: os_port.h:71
const char_t * sshGetSignFormatId(const SshString *publicKeyAlgo)
Get the signature format identifier used by a given public key algorithm.