ssh_misc.c
Go to the documentation of this file.
1 /**
2  * @file ssh_misc.c
3  * @brief SSH helper functions
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_extensions.h"
38 #include "ssh/ssh_transport.h"
39 #include "ssh/ssh_kex.h"
40 #include "ssh/ssh_kex_rsa.h"
41 #include "ssh/ssh_kex_dh.h"
42 #include "ssh/ssh_kex_dh_gex.h"
43 #include "ssh/ssh_kex_ecdh.h"
44 #include "ssh/ssh_kex_kem.h"
45 #include "ssh/ssh_kex_hybrid.h"
46 #include "ssh/ssh_auth.h"
47 #include "ssh/ssh_channel.h"
48 #include "ssh/ssh_packet.h"
49 #include "ssh/ssh_key_material.h"
50 #include "ssh/ssh_key_import.h"
51 #include "ssh/ssh_key_format.h"
52 #include "ssh/ssh_cert_import.h"
53 #include "ssh/ssh_misc.h"
54 #include "ecc/ec_misc.h"
55 #include "debug.h"
56 
57 //Check SSH stack configuration
58 #if (SSH_SUPPORT == ENABLED)
59 
60 
61 /**
62  * @brief Open a new SSH connection
63  * @param[in] context Pointer to the SSH context
64  * @param[in] socket Handle that identifies a socket
65  * @return Handle referencing the newly created SSH connection
66  **/
67 
69 {
70  error_t error;
71  uint_t i;
72  SshConnection *connection;
73 
74  //Initialize handle
75  connection = NULL;
76 
77  //Acquire exclusive access to the SSH context
78  osAcquireMutex(&context->mutex);
79 
80  //Loop through the connection table
81  for(i = 0; i < context->numConnections; i++)
82  {
83  //Unused SSH connection?
84  if(context->connections[i].state == SSH_CONN_STATE_CLOSED)
85  {
86  connection = &context->connections[i];
87  break;
88  }
89  }
90 
91  //Valid connection handle?
92  if(connection != NULL)
93  {
94  //Clear the structure describing the connection
95  osMemset(connection, 0, sizeof(SshConnection));
96 
97  //Attach SSH context
98  connection->context = context;
99  //Attach socket handle
100  connection->socket = socket;
101  //Index of the selected host key
102  connection->hostKeyIndex = -1;
103  //Initialize time stamp
104  connection->timestamp = osGetSystemTime();
105 
106  //Initialize status code
107  error = NO_ERROR;
108 
109  //Multiple callbacks may be registered
110  for(i = 0; i < SSH_MAX_CONN_OPEN_CALLBACKS && !error; i++)
111  {
112  //Valid callback function?
113  if(context->connectionOpenCallback[i] != NULL)
114  {
115  //Invoke callback function
116  error = context->connectionOpenCallback[i](connection,
117  context->connectionOpenParam[i]);
118  }
119  }
120 
121  //Check status code
122  if(!error)
123  {
124 #if (SSH_DH_KEX_SUPPORT == ENABLED || SSH_DH_GEX_KEX_SUPPORT == ENABLED)
125  //Initialize Diffie-Hellman context
126  dhInit(&connection->dhContext);
127 #endif
128 #if (SSH_ECDH_KEX_SUPPORT == ENABLED || SSH_HYBRID_KEX_SUPPORT == ENABLED)
129  //Initialize ECDH context
130  ecdhInit(&connection->ecdhContext);
131 #endif
132 #if (SSH_HYBRID_KEX_SUPPORT == ENABLED)
133  //Initialize KEM context
134  kemInit(&connection->kemContext, NULL);
135 #endif
136  //The sequence number is initialized to zero for the first packet (refer
137  //to RFC 4253, section 6.4)
138  osMemset(connection->encryptionEngine.seqNum, 0, 4);
139  osMemset(connection->decryptionEngine.seqNum, 0, 4);
140 
141  //When the connection has been established, both sides must send an
142  //identification string (refer to RFC 4253, section 4.2)
143  if(context->mode == SSH_OPERATION_MODE_CLIENT)
144  {
145  connection->state = SSH_CONN_STATE_CLIENT_ID;
146  }
147  else
148  {
149  connection->state = SSH_CONN_STATE_SERVER_ID;
150  }
151  }
152  else
153  {
154  //Clean up side effects
155  connection->socket = NULL;
156  //Return an invalid handle
157  connection = NULL;
158  }
159  }
160 
161  //Release exclusive access to the SSH context
162  osReleaseMutex(&context->mutex);
163 
164  //Return a handle to the newly created SSH connection
165  return connection;
166 }
167 
168 
169 /**
170  * @brief Close SSH connection
171  * @param[in] connection Pointer to the SSH connection
172  **/
173 
175 {
176  uint_t i;
177  SshContext *context;
178  SshChannel *channel;
179 
180  //Debug message
181  TRACE_INFO("Closing SSH connection...\r\n");
182 
183  //Point to the SSH context
184  context = connection->context;
185 
186  //Acquire exclusive access to the SSH context
187  osAcquireMutex(&context->mutex);
188 
189  //Loop through SSH channels
190  for(i = 0; i < context->numChannels; i++)
191  {
192  //Point to the current SSH channel
193  channel = &context->channels[i];
194 
195  //Multiple channels can be multiplexed into a single connection
196  if(channel->state != SSH_CHANNEL_STATE_UNUSED &&
197  channel->connection == connection)
198  {
199  //Check channel state
200  if(connection->context->mode == SSH_OPERATION_MODE_SERVER &&
201  (channel->closeRequest || !channel->channelSuccessSent))
202  {
203  //Release SSH channel
204  channel->state = SSH_CHANNEL_STATE_UNUSED;
205  }
206  else
207  {
208  //Close SSH channel
209  channel->state = SSH_CHANNEL_STATE_CLOSED;
210  //Update channel related events
211  sshUpdateChannelEvents(&context->channels[i]);
212  }
213  }
214  }
215 
216  //Valid socket handle?
217  if(connection->socket != NULL)
218  {
219  //Close TCP socket
220  socketClose(connection->socket);
221  connection->socket = NULL;
222  }
223 
224  //Deselect the host key
225  connection->hostKeyIndex = -1;
226 
227 #if (SSH_RSA_KEX_SUPPORT == ENABLED)
228  //Release server's host key
229  if(connection->serverHostKey != NULL)
230  {
231  sshFreeMem(connection->serverHostKey);
232  connection->serverHostKey = NULL;
233  connection->serverHostKeyLen = 0;
234  }
235 #endif
236 
237 #if (SSH_DH_KEX_SUPPORT == ENABLED || SSH_DH_GEX_KEX_SUPPORT == ENABLED)
238  //Release Diffie-Hellman context
239  dhFree(&connection->dhContext);
240 #endif
241 #if (SSH_ECDH_KEX_SUPPORT == ENABLED || SSH_HYBRID_KEX_SUPPORT == ENABLED)
242  //Release ECDH context
243  ecdhFree(&connection->ecdhContext);
244 #endif
245 #if (SSH_HYBRID_KEX_SUPPORT == ENABLED)
246  //Release KEM context
247  kemFree(&connection->kemContext);
248 #endif
249 
250  //Release encryption engine
251  sshFreeEncryptionEngine(&connection->encryptionEngine);
252  //Release decryption engine
253  sshFreeEncryptionEngine(&connection->decryptionEngine);
254 
255  //Multiple callbacks may be registered
256  for(i = 0; i < SSH_MAX_CONN_CLOSE_CALLBACKS; i++)
257  {
258  //Valid callback function?
259  if(context->connectionCloseCallback[i] != NULL)
260  {
261  //Invoke callback function
262  context->connectionCloseCallback[i](connection,
263  context->connectionCloseParam[i]);
264  }
265  }
266 
267  //Mark the connection as closed
268  connection->state = SSH_CONN_STATE_CLOSED;
269 
270  //Release exclusive access to the SSH context
271  osReleaseMutex(&context->mutex);
272 }
273 
274 
275 /**
276  * @brief Register connection events
277  * @param[in] context Pointer to the SSH context
278  * @param[in] connection Pointer to the SSH connection
279  * @param[in] eventDesc Socket events to be registered
280  **/
281 
283  SocketEventDesc *eventDesc)
284 {
285  uint_t i;
286 
287  //Register socket handle
288  eventDesc->socket = connection->socket;
289 
290  //On-going packet transfer?
291  if(connection->txBufferPos < connection->txBufferLen)
292  {
293  //Wait until there is more room in the send buffer
294  eventDesc->eventMask = SOCKET_EVENT_TX_READY;
295  }
296  else if(connection->rxBufferLen > 0)
297  {
298  //Wait for data to be available for reading
299  eventDesc->eventMask = SOCKET_EVENT_RX_READY;
300  }
301  else
302  {
303  //Wait for data to be available for reading
304  eventDesc->eventMask = SOCKET_EVENT_RX_READY;
305 
306  //Check the state of the connection
307  if(connection->state == SSH_CONN_STATE_CLIENT_ID ||
308  connection->state == SSH_CONN_STATE_CLIENT_KEX_INIT ||
309  connection->state == SSH_CONN_STATE_KEX_DH_INIT ||
310  connection->state == SSH_CONN_STATE_KEX_DH_GEX_REQUEST ||
311  connection->state == SSH_CONN_STATE_KEX_ECDH_INIT ||
312  connection->state == SSH_CONN_STATE_KEX_KEM_INIT ||
313  connection->state == SSH_CONN_STATE_KEX_HYBRID_INIT ||
314  connection->state == SSH_CONN_STATE_CLIENT_NEW_KEYS ||
315  connection->state == SSH_CONN_STATE_CLIENT_EXT_INFO ||
316  connection->state == SSH_CONN_STATE_SERVICE_REQUEST ||
317  connection->state == SSH_CONN_STATE_USER_AUTH_REQUEST)
318  {
319  //Client operation mode?
320  if(connection->context->mode == SSH_OPERATION_MODE_CLIENT)
321  {
322  //Wait until there is more room in the send buffer
323  eventDesc->eventMask = SOCKET_EVENT_TX_READY;
324  }
325  }
326  else if(connection->state == SSH_CONN_STATE_SERVER_ID ||
327  connection->state == SSH_CONN_STATE_SERVER_KEX_INIT ||
328  connection->state == SSH_CONN_STATE_KEX_RSA_PUB_KEY ||
329  connection->state == SSH_CONN_STATE_SERVER_NEW_KEYS ||
330  connection->state == SSH_CONN_STATE_SERVER_EXT_INFO_1 ||
331  connection->state == SSH_CONN_STATE_SERVER_EXT_INFO_2 ||
332  connection->state == SSH_CONN_STATE_USER_AUTH_SUCCESS)
333  {
334  //Server operation mode?
335  if(connection->context->mode == SSH_OPERATION_MODE_SERVER)
336  {
337  //Wait until there is more room in the send buffer
338  eventDesc->eventMask = SOCKET_EVENT_TX_READY;
339  }
340  }
341  else if(connection->state == SSH_CONN_STATE_OPEN)
342  {
343  //Loop through SSH channels
344  for(i = 0; i < context->numChannels; i++)
345  {
346  //Multiple channels can be multiplexed into a single connection
347  if(context->channels[i].state != SSH_CHANNEL_STATE_UNUSED &&
348  context->channels[i].connection == connection)
349  {
350  //Register the events related to the current SSH channel
351  sshRegisterChannelEvents(&context->channels[i], eventDesc);
352  }
353  }
354  }
355  else if(connection->state == SSH_CONN_STATE_DISCONNECT)
356  {
357  //Wait until there is more room in the send buffer
358  eventDesc->eventMask = SOCKET_EVENT_TX_READY;
359  }
360  else
361  {
362  //Just for sanity
363  }
364  }
365 }
366 
367 
368 /**
369  * @brief Connection event handler
370  * @param[in] context Pointer to the SSH context
371  * @param[in] connection Pointer to the SSH connection
372  * @return Error code
373  **/
374 
376  SshConnection *connection)
377 {
378  error_t error;
379  uint_t i;
380  size_t n;
381 
382  //Initialize status code
383  error = NO_ERROR;
384 
385  //Update time stamp
386  connection->timestamp = osGetSystemTime();
387 
388  //The SSH Connection Protocol has been designed to run on top of the SSH
389  //transport layer and user authentication protocols
390  if(connection->state == SSH_CONN_STATE_OPEN)
391  {
392  //Loop through SSH channels
393  for(i = 0; i < context->numChannels && !error; i++)
394  {
395  //Multiple channels can be multiplexed into a single connection
396  if(context->channels[i].state != SSH_CHANNEL_STATE_UNUSED &&
397  context->channels[i].connection == connection)
398  {
399  //Check whether the connection is ready for transmission
400  if(connection->txBufferLen == 0 && connection->rxBufferLen == 0)
401  {
402  //Process channel related events
403  error = sshProcessChannelEvents(&context->channels[i]);
404  }
405  }
406  }
407  }
408 
409  //Check status code
410  if(!error)
411  {
412  //On-going packet transmission?
413  if(connection->txBufferPos < connection->txBufferLen)
414  {
415  //Send more data
416  error = socketSend(connection->socket,
417  connection->buffer + connection->txBufferPos,
418  connection->txBufferLen - connection->txBufferPos, &n, 0);
419 
420  //Check status code
421  if(error == NO_ERROR || error == ERROR_TIMEOUT)
422  {
423  //Advance data pointer
424  connection->txBufferPos += n;
425 
426  //Check whether the transmission is complete
427  if(connection->txBufferPos >= connection->txBufferLen)
428  {
429  //Flush transmit buffer
430  connection->txBufferLen = 0;
431  connection->txBufferPos = 0;
432  }
433  }
434  }
435  else
436  {
437 #if (SSH_CLIENT_SUPPORT == ENABLED)
438  //Client operation mode?
439  if(connection->context->mode == SSH_OPERATION_MODE_CLIENT)
440  {
441  //Check the state of the connection
442  if(connection->state == SSH_CONN_STATE_CLIENT_ID)
443  {
444  //Send client's identification string
445  error = sshSendIdString(connection);
446  }
447  else if(connection->state == SSH_CONN_STATE_CLIENT_KEX_INIT)
448  {
449  //Send SSH_MSG_KEXINIT message
450  error = sshSendKexInit(connection);
451  }
452 #if (SSH_DH_KEX_SUPPORT == ENABLED)
453  else if(connection->state == SSH_CONN_STATE_KEX_DH_INIT)
454  {
455  //Send SSH_MSG_KEX_DH_INIT message
456  error = sshSendKexDhInit(connection);
457  }
458 #endif
459 #if (SSH_DH_GEX_KEX_SUPPORT == ENABLED)
460  else if(connection->state == SSH_CONN_STATE_KEX_DH_GEX_REQUEST)
461  {
462  //Send SSH_MSG_KEY_DH_GEX_REQUEST message
463  error = sshSendKexDhGexRequest(connection);
464  }
465 #endif
466 #if (SSH_ECDH_KEX_SUPPORT == ENABLED)
467  else if(connection->state == SSH_CONN_STATE_KEX_ECDH_INIT)
468  {
469  //Send SSH_MSG_KEX_ECDH_INIT message
470  error = sshSendKexEcdhInit(connection);
471  }
472 #endif
473 #if (SSH_KEM_KEX_SUPPORT == ENABLED)
474  else if(connection->state == SSH_CONN_STATE_KEX_KEM_INIT)
475  {
476  //Send SSH_MSG_KEX_KEM_INIT message
477  error = sshSendKexKemInit(connection);
478  }
479 #endif
480 #if (SSH_HYBRID_KEX_SUPPORT == ENABLED)
481  else if(connection->state == SSH_CONN_STATE_KEX_HYBRID_INIT)
482  {
483  //Send SSH_MSG_KEX_HYBRID_INIT message
484  error = sshSendKexHybridInit(connection);
485  }
486 #endif
487 #if (SSH_EXT_INFO_SUPPORT == ENABLED)
488  else if(connection->state == SSH_CONN_STATE_CLIENT_EXT_INFO)
489  {
490  //Send SSH_MSG_EXT_INFO message
491  error = sshSendExtInfo(connection);
492  }
493 #endif
494  else if(connection->state == SSH_CONN_STATE_SERVICE_REQUEST)
495  {
496  //Send SSH_MSG_SERVICE_REQUEST message
497  error = sshSendServiceRequest(connection);
498  }
499  else if(connection->state == SSH_CONN_STATE_USER_AUTH_REQUEST)
500  {
501  //Send SSH_MSG_USERAUTH_REQUEST message
502  error = sshSendUserAuthRequest(connection);
503  }
504  else if(connection->state == SSH_CONN_STATE_SERVER_ID ||
505  connection->state == SSH_CONN_STATE_SERVER_KEX_INIT ||
506  connection->state == SSH_CONN_STATE_KEX_RSA_PUB_KEY ||
507  connection->state == SSH_CONN_STATE_KEX_RSA_DONE ||
508  connection->state == SSH_CONN_STATE_KEX_DH_REPLY ||
509  connection->state == SSH_CONN_STATE_KEX_DH_GEX_GROUP ||
510  connection->state == SSH_CONN_STATE_KEX_DH_GEX_REPLY ||
511  connection->state == SSH_CONN_STATE_KEX_ECDH_REPLY ||
512  connection->state == SSH_CONN_STATE_KEX_KEM_REPLY ||
513  connection->state == SSH_CONN_STATE_KEX_HYBRID_REPLY ||
514  connection->state == SSH_CONN_STATE_SERVER_NEW_KEYS ||
515  connection->state == SSH_CONN_STATE_SERVER_EXT_INFO_1 ||
516  connection->state == SSH_CONN_STATE_SERVER_EXT_INFO_2 ||
517  connection->state == SSH_CONN_STATE_SERVICE_ACCEPT ||
518  connection->state == SSH_CONN_STATE_USER_AUTH_REPLY ||
519  connection->state == SSH_CONN_STATE_USER_AUTH_SUCCESS ||
520  connection->state == SSH_CONN_STATE_OPEN)
521  {
522  //Receive incoming packet
523  error = sshReceivePacket(connection);
524  }
525  else if(connection->state == SSH_CONN_STATE_DISCONNECT)
526  {
527  //The SSH_MSG_DISCONNECT message causes immediate termination of
528  //the connection
529  error = ERROR_CONNECTION_CLOSING;
530  }
531  else
532  {
533  //Invalid state
534  error = ERROR_WRONG_STATE;
535  }
536  }
537  else
538 #endif
539 #if (SSH_SERVER_SUPPORT == ENABLED)
540  //Server operation mode?
541  if(connection->context->mode == SSH_OPERATION_MODE_SERVER)
542  {
543  //Check the state of the connection
544  if(connection->state == SSH_CONN_STATE_SERVER_ID)
545  {
546  //Send server's identification string
547  error = sshSendIdString(connection);
548  }
549  else if(connection->state == SSH_CONN_STATE_SERVER_KEX_INIT)
550  {
551  //Send SSH_MSG_KEXINIT message
552  error = sshSendKexInit(connection);
553  }
554 #if (SSH_RSA_KEX_SUPPORT == ENABLED)
555  else if(connection->state == SSH_CONN_STATE_KEX_RSA_PUB_KEY)
556  {
557  //Send SSH_MSG_KEXRSA_PUBKEY message
558  error = sshSendKexRsaPubKey(connection);
559  }
560 #endif
561  else if(connection->state == SSH_CONN_STATE_SERVER_NEW_KEYS)
562  {
563  //Send SSH_MSG_NEWKEYS message
564  error = sshSendNewKeys(connection);
565  }
566 #if (SSH_EXT_INFO_SUPPORT == ENABLED)
567  else if(connection->state == SSH_CONN_STATE_SERVER_EXT_INFO_1 ||
568  connection->state == SSH_CONN_STATE_SERVER_EXT_INFO_2)
569  {
570  //Send SSH_MSG_EXT_INFO message
571  error = sshSendExtInfo(connection);
572  }
573 #endif
574  else if(connection->state == SSH_CONN_STATE_USER_AUTH_SUCCESS)
575  {
576  //Send SSH_MSG_USERAUTH_SUCCESS message
577  error = sshSendUserAuthSuccess(connection);
578  }
579  else if(connection->state == SSH_CONN_STATE_CLIENT_ID ||
580  connection->state == SSH_CONN_STATE_CLIENT_KEX_INIT ||
581  connection->state == SSH_CONN_STATE_KEX_RSA_SECRET ||
582  connection->state == SSH_CONN_STATE_KEX_DH_INIT ||
583  connection->state == SSH_CONN_STATE_KEX_DH_GEX_REQUEST ||
584  connection->state == SSH_CONN_STATE_KEX_DH_GEX_INIT ||
585  connection->state == SSH_CONN_STATE_KEX_ECDH_INIT ||
586  connection->state == SSH_CONN_STATE_KEX_KEM_INIT ||
587  connection->state == SSH_CONN_STATE_KEX_HYBRID_INIT ||
588  connection->state == SSH_CONN_STATE_CLIENT_NEW_KEYS ||
589  connection->state == SSH_CONN_STATE_CLIENT_EXT_INFO ||
590  connection->state == SSH_CONN_STATE_SERVICE_REQUEST ||
591  connection->state == SSH_CONN_STATE_USER_AUTH_REQUEST ||
592  connection->state == SSH_CONN_STATE_OPEN)
593  {
594  //Receive incoming packet
595  error = sshReceivePacket(connection);
596  }
597  else if(connection->state == SSH_CONN_STATE_DISCONNECT)
598  {
599  //The SSH_MSG_DISCONNECT message causes immediate termination of
600  //the connection
601  error = ERROR_CONNECTION_CLOSING;
602  }
603  else
604  {
605  //Invalid state
606  error = ERROR_WRONG_STATE;
607  }
608  }
609  else
610 #endif
611  //Invalid operation mode?
612  {
613  //Report an error
614  error = ERROR_FAILURE;
615  }
616  }
617  }
618 
619  //Return status code
620  return error;
621 }
622 
623 
624 /**
625  * @brief Subscribe to the specified channel events
626  * @param[in] channel Handle referencing an SSH channel
627  * @param[in] event Event object used to receive notifications
628  * @param[in] eventMask Logic OR of the requested socket events
629  **/
630 
632  uint_t eventMask)
633 {
634  //Valid channel handle?
635  if(channel != NULL)
636  {
637  //Acquire exclusive access to the SSH context
638  osAcquireMutex(&channel->context->mutex);
639 
640  //An user event may have been previously registered...
641  if(channel->userEvent != NULL)
642  {
643  channel->eventMask |= eventMask;
644  }
645  else
646  {
647  channel->eventMask = eventMask;
648  }
649 
650  //Suscribe to get notified of events
651  channel->userEvent = event;
652  //Update channel related events
653  sshUpdateChannelEvents(channel);
654 
655  //Release exclusive access to the SSH context
656  osReleaseMutex(&channel->context->mutex);
657  }
658 }
659 
660 
661 /**
662  * @brief Unsubscribe previously registered events
663  * @param[in] channel Handle referencing an SSH channel
664  **/
665 
667 {
668  //Valid channel handle?
669  if(channel != NULL)
670  {
671  //Acquire exclusive access to the SSH context
672  osAcquireMutex(&channel->context->mutex);
673 
674  //Unsuscribe channel events
675  channel->userEvent = NULL;
676 
677  //Release exclusive access to the SSH context
678  osReleaseMutex(&channel->context->mutex);
679  }
680 }
681 
682 
683 /**
684  * @brief Retrieve event flags for a specified channel
685  * @param[in] channel Handle referencing an SSH channel
686  * @return Logic OR of events in the signaled state
687  **/
688 
690 {
691  uint_t eventFlags;
692 
693  //Valid channel handle?
694  if(channel != NULL)
695  {
696  //Acquire exclusive access to the SSH context
697  osAcquireMutex(&channel->context->mutex);
698 
699  //Read event flags for the specified socket
700  eventFlags = channel->eventFlags;
701 
702  //Release exclusive access to the SSH context
703  osReleaseMutex(&channel->context->mutex);
704  }
705  else
706  {
707  //The socket handle is not valid
708  eventFlags = 0;
709  }
710 
711  //Return the events in the signaled state
712  return eventFlags;
713 }
714 
715 
716 /**
717  * @brief Notify the SSH context that event is occurring
718  * @param[in] context Pointer to the SSH context
719  **/
720 
722 {
723  //Notify the SSH context that event is occurring
724  osSetEvent(&context->event);
725 }
726 
727 
728 /**
729  * @brief Get the currently selected host key
730  * @param[in] connection Pointer to the SSH connection
731  * @return Pointer to the selected host key
732  **/
733 
735 {
736  SshContext *context;
737  SshHostKey *hostKey;
738 
739  //Point to the SSH context
740  context = connection->context;
741 
742  //No host key is currently selected
743  hostKey = NULL;
744 
745  //Ensure the index is valid
746  if(connection->hostKeyIndex >= 0 &&
747  connection->hostKeyIndex < SSH_MAX_HOST_KEYS)
748  {
749  //Valid host key?
750  if(context->hostKeys[connection->hostKeyIndex].keyFormatId != NULL)
751  {
752  //Point to the selected host key
753  hostKey = &context->hostKeys[connection->hostKeyIndex];
754  }
755  }
756 
757  //Return the selected host key
758  return hostKey;
759 }
760 
761 
762 /**
763  * @brief Select a host key that matches then specified algorithm
764  * @param[in] context Pointer to the SSH context
765  * @param[in] hostKeyAlgo Selected host key algorithm name
766  * @return Index of the selected host key, if any
767  **/
768 
769 int_t sshSelectHostKey(SshContext *context, const char_t *hostKeyAlgo)
770 {
771  int_t i;
772  int_t index;
773  SshString name;
774  SshHostKey *hostKey;
775  const char_t *keyFormatId;
776 
777  //Initialize index
778  index = -1;
779 
780  //Get the name of the selected host key algorithm
781  name.value = hostKeyAlgo;
782  name.length = osStrlen(hostKeyAlgo);
783 
784  //Retrieve the corresponding key format identifier
785  keyFormatId = sshGetKeyFormatId(&name);
786 
787  //Valid key format identifier?
788  if(keyFormatId != NULL)
789  {
790  //Loop through the host keys
791  for(i = 0; i < SSH_MAX_HOST_KEYS && index < 0; i++)
792  {
793  //Point to the current host key
794  hostKey = &context->hostKeys[i];
795 
796  //Valid host key?
797  if(hostKey->keyFormatId != NULL)
798  {
799  //Compare key format identifiers
800  if(sshCompareAlgo(hostKey->keyFormatId, keyFormatId))
801  {
802  //The current host key is acceptable
803  index = i;
804  }
805  }
806  }
807  }
808 
809  //Return the index of the host key
810  return index;
811 }
812 
813 
814 /**
815  * @brief Select the next acceptable host key
816  * @param[in] connection Pointer to the SSH connection
817  * @return Index of the next acceptable host key, if any
818  **/
819 
821 {
822 #if (SSH_CLIENT_SUPPORT == ENABLED)
823  int_t index;
824  SshHostKey *hostKey;
825 
826  //Initialize index
827  index = -1;
828 
829  //Loop through the host keys
830  while(connection->hostKeyIndex < SSH_MAX_HOST_KEYS)
831  {
832  //Increment index
833  if(connection->hostKeyIndex < 0)
834  {
835  connection->hostKeyIndex = 0;
836  }
837  else
838  {
839  connection->hostKeyIndex++;
840  }
841 
842  //Point to the corresponding host key
843  hostKey = sshGetHostKey(connection);
844 
845  //Valid host key?
846  if(hostKey != NULL)
847  {
848  //Make sure the public key algorithm is valid
849  if(hostKey->publicKeyAlgo != NULL)
850  {
851  //The current host key is acceptable
852  index = connection->hostKeyIndex;
853  break;
854  }
855  }
856  }
857 
858  //Return the index of the next acceptable host key, if any
859  return index;
860 #else
861  //Client operation mode is not implemented
862  return -1;
863 #endif
864 }
865 
866 
867 /**
868  * @brief Format host key structure
869  * @param[in] connection Pointer to the SSH connection
870  * @param[out] p Output stream where to write the host key
871  * @param[out] written Total number of bytes that have been written
872  * @return Error code
873  **/
874 
875 error_t sshFormatHostKey(SshConnection *connection, uint8_t *p,
876  size_t *written)
877 {
878  error_t error;
879  SshHostKey *hostKey;
880 
881  //Get the currently selected host key
882  hostKey = sshGetHostKey(connection);
883 
884  //Valid host key?
885  if(hostKey != NULL)
886  {
887 #if (SSH_RSA_SIGN_SUPPORT == ENABLED)
888  //RSA host key?
889  if(sshCompareAlgo(hostKey->keyFormatId, "ssh-rsa"))
890  {
891  RsaPublicKey rsaPublicKey;
892 
893  //Initialize RSA public key
894  rsaInitPublicKey(&rsaPublicKey);
895 
896  //Load RSA public key
897  error = sshImportRsaPublicKey(&rsaPublicKey, hostKey->publicKey,
898  hostKey->publicKeyLen);
899 
900  //Check status code
901  if(!error)
902  {
903  //Format RSA host key structure
904  error = sshFormatRsaPublicKey(&rsaPublicKey, p, written);
905  }
906 
907  //Free previously allocated resources
908  rsaFreePublicKey(&rsaPublicKey);
909  }
910  else
911 #endif
912 #if (SSH_RSA_SIGN_SUPPORT == ENABLED && SSH_CERT_SUPPORT == ENABLED)
913  //RSA certificate?
914  if(sshCompareAlgo(hostKey->keyFormatId, "ssh-rsa-cert") ||
915  sshCompareAlgo(hostKey->keyFormatId, "ssh-rsa-cert-v01@openssh.com"))
916  {
917  //Extract RSA certificate
918  error = sshImportCertificate(hostKey->publicKey, hostKey->publicKeyLen,
919  p, written);
920  }
921  else
922 #endif
923 #if (SSH_DSA_SIGN_SUPPORT == ENABLED)
924  //DSA host key?
925  if(sshCompareAlgo(hostKey->keyFormatId, "ssh-dss"))
926  {
927  DsaPublicKey dsaPublicKey;
928 
929  //Initialize DSA public key
930  dsaInitPublicKey(&dsaPublicKey);
931 
932  //Load DSA public key
933  error = sshImportDsaPublicKey(&dsaPublicKey, hostKey->publicKey,
934  hostKey->publicKeyLen);
935 
936  //Check status code
937  if(!error)
938  {
939  //Format DSA host key structure
940  error = sshFormatDsaPublicKey(&dsaPublicKey, p, written);
941  }
942 
943  //Free previously allocated resources
944  dsaFreePublicKey(&dsaPublicKey);
945  }
946  else
947 #endif
948 #if (SSH_DSA_SIGN_SUPPORT == ENABLED && SSH_CERT_SUPPORT == ENABLED)
949  //DSA certificate?
950  if(sshCompareAlgo(hostKey->keyFormatId, "ssh-dss-cert") ||
951  sshCompareAlgo(hostKey->keyFormatId, "ssh-dss-cert-v01@openssh.com"))
952  {
953  //Extract DSA certificate
954  error = sshImportCertificate(hostKey->publicKey, hostKey->publicKeyLen,
955  p, written);
956  }
957  else
958 #endif
959 #if (SSH_ECDSA_SIGN_SUPPORT == ENABLED)
960  //ECDSA host key?
961  if(sshCompareAlgo(hostKey->keyFormatId, "ecdsa-sha2-nistp256") ||
962  sshCompareAlgo(hostKey->keyFormatId, "ecdsa-sha2-nistp384") ||
963  sshCompareAlgo(hostKey->keyFormatId, "ecdsa-sha2-nistp521"))
964  {
965  EcPublicKey ecPublicKey;
966 
967  //Initialize ECDSA public key
968  ecInitPublicKey(&ecPublicKey);
969 
970  //Load ECDSA public key
971  error = sshImportEcdsaPublicKey(&ecPublicKey, hostKey->publicKey,
972  hostKey->publicKeyLen);
973 
974  //Check status code
975  if(!error)
976  {
977  //Format ECDSA host key structure
978  error = sshFormatEcdsaPublicKey(&ecPublicKey, p, written);
979  }
980 
981  //Free previously allocated resources
982  ecFreePublicKey(&ecPublicKey);
983  }
984  else
985 #endif
986 #if (SSH_ECDSA_SIGN_SUPPORT == ENABLED && SSH_CERT_SUPPORT == ENABLED)
987  //ECDSA certificate?
988  if(sshCompareAlgo(hostKey->keyFormatId, "ecdsa-sha2-nistp256-cert") ||
989  sshCompareAlgo(hostKey->keyFormatId, "ecdsa-sha2-nistp384-cert") ||
990  sshCompareAlgo(hostKey->keyFormatId, "ecdsa-sha2-nistp521-cert") ||
991  sshCompareAlgo(hostKey->keyFormatId, "ecdsa-sha2-nistp256-cert-v01@openssh.com") ||
992  sshCompareAlgo(hostKey->keyFormatId, "ecdsa-sha2-nistp384-cert-v01@openssh.com") ||
993  sshCompareAlgo(hostKey->keyFormatId, "ecdsa-sha2-nistp521-cert-v01@openssh.com"))
994  {
995  //Extract ECDSA certificate
996  error = sshImportCertificate(hostKey->publicKey, hostKey->publicKeyLen,
997  p, written);
998  }
999  else
1000 #endif
1001 #if (SSH_ED25519_SIGN_SUPPORT == ENABLED)
1002  //Ed25519 host key?
1003  if(sshCompareAlgo(hostKey->keyFormatId, "ssh-ed25519"))
1004  {
1005  EddsaPublicKey eddsaPublicKey;
1006 
1007  //Initialize EdDSA public key
1008  eddsaInitPublicKey(&eddsaPublicKey);
1009 
1010  //Load EdDSA public key
1011  error = sshImportEd25519PublicKey(&eddsaPublicKey, hostKey->publicKey,
1012  hostKey->publicKeyLen);
1013 
1014  //Check status code
1015  if(!error)
1016  {
1017  //Format Ed25519 host key structure
1018  error = sshFormatEd25519PublicKey(&eddsaPublicKey, p, written);
1019  }
1020 
1021  //Free previously allocated resources
1022  eddsaFreePublicKey(&eddsaPublicKey);
1023  }
1024  else
1025 #endif
1026 #if (SSH_ED25519_SIGN_SUPPORT == ENABLED && SSH_CERT_SUPPORT == ENABLED)
1027  //Ed25519 certificate?
1028  if(sshCompareAlgo(hostKey->keyFormatId, "ssh-ed25519-cert") ||
1029  sshCompareAlgo(hostKey->keyFormatId, "ssh-ed25519-cert-v01@openssh.com"))
1030  {
1031  //Extract EdDSA certificate
1032  error = sshImportCertificate(hostKey->publicKey, hostKey->publicKeyLen,
1033  p, written);
1034  }
1035  else
1036 #endif
1037 #if (SSH_ED448_SIGN_SUPPORT == ENABLED)
1038  //Ed448 host key?
1039  if(sshCompareAlgo(hostKey->keyFormatId, "ssh-ed448"))
1040  {
1041  EddsaPublicKey eddsaPublicKey;
1042 
1043  //Initialize EdDSA public key
1044  eddsaInitPublicKey(&eddsaPublicKey);
1045 
1046  //Load EdDSA public key
1047  error = sshImportEd448PublicKey(&eddsaPublicKey, hostKey->publicKey,
1048  hostKey->publicKeyLen);
1049 
1050  //Check status code
1051  if(!error)
1052  {
1053  //Format Ed448 host key structure
1054  error = sshFormatEd448PublicKey(&eddsaPublicKey, p, written);
1055  }
1056 
1057  //Free previously allocated resources
1058  eddsaFreePublicKey(&eddsaPublicKey);
1059  }
1060  else
1061 #endif
1062 #if (SSH_ED448_SIGN_SUPPORT == ENABLED && SSH_CERT_SUPPORT == ENABLED)
1063  //Ed448 certificate?
1064  if(sshCompareAlgo(hostKey->keyFormatId, "ssh-ed448-cert"))
1065  {
1066  //Extract EdDSA certificate
1067  error = sshImportCertificate(hostKey->publicKey, hostKey->publicKeyLen,
1068  p, written);
1069  }
1070  else
1071 #endif
1072  //Unknown host key type?
1073  {
1074  //Report an error
1075  error = ERROR_INVALID_KEY;
1076  }
1077  }
1078  else
1079  {
1080  //No host key is currently selected
1081  error = ERROR_INVALID_KEY;
1082  }
1083 
1084  //Return status code
1085  return error;
1086 }
1087 
1088 
1089 /**
1090  * @brief Get the elliptic curve that matches the specified key format identifier
1091  * @param[in] keyFormatId Key format identifier
1092  * @param[in] curveName Curve name
1093  * @return Elliptic curve parameters
1094  **/
1095 
1096 const EcCurve *sshGetCurve(const SshString *keyFormatId,
1097  const SshString *curveName)
1098 {
1099  const EcCurve *curve;
1100 
1101 #if (SSH_ECDSA_SIGN_SUPPORT == ENABLED)
1102 #if (SSH_NISTP256_SUPPORT == ENABLED)
1103  //NIST P-256 elliptic curve?
1104  if(sshCompareString(keyFormatId, "ecdsa-sha2-nistp256") &&
1105  sshCompareString(curveName, "nistp256"))
1106  {
1107  curve = SECP256R1_CURVE;
1108  }
1109  else
1110 #endif
1111 #if (SSH_NISTP256_SUPPORT == ENABLED && SSH_CERT_SUPPORT == ENABLED)
1112  //NIST P-256 elliptic curve?
1113  if((sshCompareString(keyFormatId, "ecdsa-sha2-nistp256-cert") ||
1114  sshCompareString(keyFormatId, "ecdsa-sha2-nistp256-cert-v01@openssh.com")) &&
1115  sshCompareString(curveName, "nistp256"))
1116  {
1117  curve = SECP256R1_CURVE;
1118  }
1119  else
1120 #endif
1121 #if (SSH_NISTP384_SUPPORT == ENABLED)
1122  //NIST P-384 elliptic curve?
1123  if(sshCompareString(keyFormatId, "ecdsa-sha2-nistp384") &&
1124  sshCompareString(curveName, "nistp384"))
1125  {
1126  curve = SECP384R1_CURVE;
1127  }
1128  else
1129 #endif
1130 #if (SSH_NISTP384_SUPPORT == ENABLED && SSH_CERT_SUPPORT == ENABLED)
1131  //NIST P-384 elliptic curve?
1132  if((sshCompareString(keyFormatId, "ecdsa-sha2-nistp384-cert") ||
1133  sshCompareString(keyFormatId, "ecdsa-sha2-nistp384-cert-v01@openssh.com")) &&
1134  sshCompareString(curveName, "nistp384"))
1135  {
1136  curve = SECP384R1_CURVE;
1137  }
1138  else
1139 #endif
1140 #if (SSH_NISTP521_SUPPORT == ENABLED)
1141  //NIST P-521 elliptic curve?
1142  if(sshCompareString(keyFormatId, "ecdsa-sha2-nistp521") &&
1143  sshCompareString(curveName, "nistp521"))
1144  {
1145  curve = SECP521R1_CURVE;
1146  }
1147  else
1148 #endif
1149 #if (SSH_NISTP521_SUPPORT == ENABLED && SSH_CERT_SUPPORT == ENABLED)
1150  //NIST P-521 elliptic curve?
1151  if((sshCompareString(keyFormatId, "ecdsa-sha2-nistp521-cert") ||
1152  sshCompareString(keyFormatId, "ecdsa-sha2-nistp521-cert-v01@openssh.com")) &&
1153  sshCompareString(curveName, "nistp521"))
1154  {
1155  curve = SECP521R1_CURVE;
1156  }
1157  else
1158 #endif
1159 #endif
1160  //Unknow elliptic curve?
1161  {
1162  curve = NULL;
1163  }
1164 
1165  //Return the elliptic curve parameters, if any
1166  return curve;
1167 }
1168 
1169 
1170 /**
1171  * @brief Parse a string
1172  * @param[in] p Input stream where to read the string
1173  * @param[in] length Number of bytes available in the input stream
1174  * @param[out] string String resulting from the parsing process
1175  * @return Error code
1176  **/
1177 
1178 error_t sshParseString(const uint8_t *p, size_t length, SshString *string)
1179 {
1180  size_t n;
1181 
1182  //Malformed data?
1183  if(length < sizeof(uint32_t))
1184  return ERROR_INVALID_SYNTAX;
1185 
1186  //A string is stored as a uint32 containing its length and zero or more
1187  //bytes that are the value of the string
1188  n = LOAD32BE(p);
1189 
1190  //Point to the value of the string
1191  p += sizeof(uint32_t);
1192  length -= sizeof(uint32_t);
1193 
1194  //Malformed data?
1195  if(length < n)
1196  return ERROR_INVALID_SYNTAX;
1197 
1198  //Save the value of the string
1199  string->value = (char_t *) p;
1200  string->length = n;
1201 
1202  //Successful processing
1203  return NO_ERROR;
1204 }
1205 
1206 
1207 /**
1208  * @brief Parse a binary string
1209  * @param[in] p Input stream where to read the string
1210  * @param[in] length Number of bytes available in the input stream
1211  * @param[out] string Binary string resulting from the parsing process
1212  * @return Error code
1213  **/
1214 
1215 error_t sshParseBinaryString(const uint8_t *p, size_t length,
1216  SshBinaryString *string)
1217 {
1218  size_t n;
1219 
1220  //Malformed data?
1221  if(length < sizeof(uint32_t))
1222  return ERROR_INVALID_SYNTAX;
1223 
1224  //A string is stored as a uint32 containing its length and zero or more
1225  //bytes that are the value of the string
1226  n = LOAD32BE(p);
1227 
1228  //Point to the value of the string
1229  p += sizeof(uint32_t);
1230  length -= sizeof(uint32_t);
1231 
1232  //Malformed data?
1233  if(length < n)
1234  return ERROR_INVALID_SYNTAX;
1235 
1236  //Save the value of the string
1237  string->value = p;
1238  string->length = n;
1239 
1240  //Successful processing
1241  return NO_ERROR;
1242 }
1243 
1244 
1245 /**
1246  * @brief Parse a comma-separated list of names
1247  * @param[in] p Input stream where to read the list
1248  * @param[in] length Number of bytes available in the input stream
1249  * @param[out] nameList Name list resulting from the parsing process
1250  * @return Error code
1251  **/
1252 
1253 error_t sshParseNameList(const uint8_t *p, size_t length,
1254  SshNameList *nameList)
1255 {
1256  size_t i;
1257  size_t n;
1258 
1259  //Malformed data?
1260  if(length < sizeof(uint32_t))
1261  return ERROR_INVALID_SYNTAX;
1262 
1263  //A name-list is represented as a uint32 containing its length followed by
1264  //a comma-separated list of zero or more names
1265  n = LOAD32BE(p);
1266 
1267  //Point to the list of names
1268  p += sizeof(uint32_t);
1269  length -= sizeof(uint32_t);
1270 
1271  //Malformed data?
1272  if(length < n)
1273  return ERROR_INVALID_SYNTAX;
1274 
1275  //Loop through the comma-separated list of names
1276  for(i = 0; i < n; i++)
1277  {
1278  //A name must have a non-zero length (refer to RFC 4251 section 5)
1279  if(i == 0 || i == (n - 1))
1280  {
1281  if(p[i] == ',')
1282  return ERROR_INVALID_SYNTAX;
1283  }
1284  else
1285  {
1286  if(p[i] == ',' && p[i - 1] == ',')
1287  return ERROR_INVALID_SYNTAX;
1288  }
1289 
1290  //Terminating null characters must not be used, neither for the
1291  //individual names, nor for the list as a whole
1292  if(p[i] == '\0')
1293  return ERROR_INVALID_SYNTAX;
1294  }
1295 
1296  //Save the list of names
1297  nameList->value = (char_t *) p;
1298  nameList->length = n;
1299 
1300  //Successful processing
1301  return NO_ERROR;
1302 }
1303 
1304 
1305 /**
1306  * @brief Search a name list for a given name
1307  * @param[in] nameList List of names
1308  * @param[in] name NULL-terminated string containing the name
1309  * @return The index of the name, or -1 if the name does not appear in the
1310  * name list
1311  **/
1312 
1313 int_t sshFindName(const SshNameList *nameList, const char_t *name)
1314 {
1315  size_t i;
1316  size_t j;
1317  uint_t index;
1318  size_t nameLen;
1319 
1320  //Retrieve the length of the name
1321  nameLen = osStrlen(name);
1322 
1323  //Initialize variables
1324  i = 0;
1325  index = 0;
1326 
1327  //Loop through the list of names
1328  for(j = 0; j <= nameList->length; j++)
1329  {
1330  //Names are separated by commas
1331  if(j == nameList->length || nameList->value[j] == ',')
1332  {
1333  //Check the length of the name
1334  if(nameLen == (j - i))
1335  {
1336  //Matching name?
1337  if(osMemcmp(nameList->value + i, name, nameLen) == 0)
1338  {
1339  //Return the index of the name
1340  return index;
1341  }
1342  }
1343 
1344  //Point to the next name of the list
1345  i = j + 1;
1346  //Increment index
1347  index++;
1348  }
1349  }
1350 
1351  //The name does not appear in the name list
1352  return -1;
1353 }
1354 
1355 
1356 /**
1357  * @brief Get the element at specified index
1358  * @param[in] nameList List of names
1359  * @param[in] index Zero-based index of the element to get
1360  * @param[out] name Value of the element
1361  * @return TRUE if the index is valid, else FALSE
1362  **/
1363 
1365 {
1366  size_t i;
1367  size_t j;
1368  uint_t n;
1369 
1370  //Initialize variables
1371  i = 0;
1372  n = 0;
1373 
1374  //Loop through the list of names
1375  for(j = 0; j <= nameList->length; j++)
1376  {
1377  //Names are separated by commas
1378  if(j == nameList->length || nameList->value[j] == ',')
1379  {
1380  //Matching index?
1381  if(n++ == index)
1382  {
1383  //Point to first character of the name
1384  name->value = nameList->value + i;
1385  //Determine the length of the name
1386  name->length = j - i;
1387 
1388  //The index is valid
1389  return TRUE;
1390  }
1391 
1392  //Point to the next name of the list
1393  i = j + 1;
1394  }
1395  }
1396 
1397  //The index is out of range
1398  return FALSE;
1399 }
1400 
1401 
1402 /**
1403  * @brief Format a string
1404  * @param[in] value NULL-terminating string
1405  * @param[out] p Output stream where to write the string
1406  * @param[out] written Total number of bytes that have been written
1407  * @return Error code
1408  **/
1409 
1410 error_t sshFormatString(const char_t *value, uint8_t *p, size_t *written)
1411 {
1412  size_t n;
1413 
1414  //Retrieve the length of the string
1415  n = osStrlen(value);
1416 
1417  //If the output parameter is NULL, then the function calculates the length
1418  //of the string without copying any data
1419  if(p != NULL)
1420  {
1421  //A string is stored as a uint32 containing its length and zero or more
1422  //bytes that are the value of the string
1423  STORE32BE(n, p);
1424 
1425  //Copy the value of the string
1426  osMemcpy(p + sizeof(uint32_t), value, n);
1427  }
1428 
1429  //Total number of bytes that have been written
1430  *written = sizeof(uint32_t) + n;
1431 
1432  //Successful processing
1433  return NO_ERROR;
1434 }
1435 
1436 
1437 /**
1438  * @brief Format a binary string
1439  * @param[in] value Pointer to the binary string
1440  * @param[in] valueLen Length of the binary string, in bytes
1441  * @param[out] p Output stream where to write the binary string
1442  * @param[out] written Total number of bytes that have been written
1443  * @return Error code
1444  **/
1445 
1446 error_t sshFormatBinaryString(const void *value, size_t valueLen, uint8_t *p,
1447  size_t *written)
1448 {
1449  //A string is stored as a uint32 containing its length and zero or more
1450  //bytes that are the value of the string
1451  STORE32BE(valueLen, p);
1452 
1453  //Copy the value of the string
1454  osMemcpy(p + sizeof(uint32_t), value, valueLen);
1455 
1456  //Total number of bytes that have been written
1457  *written = sizeof(uint32_t) + valueLen;
1458 
1459  //Successful processing
1460  return NO_ERROR;
1461 }
1462 
1463 
1464 /**
1465  * @brief Format a comma-separated list of names
1466  * @param[in] nameList List of names
1467  * @param[in] nameListLen Number of items in the list
1468  * @param[out] p Output stream where to write the name list
1469  * @param[out] written Total number of bytes that have been written
1470  * @return Error code
1471  **/
1472 
1473 error_t sshFormatNameList(const char_t *const nameList[], uint_t nameListLen,
1474  uint8_t *p, size_t *written)
1475 {
1476  uint_t i;
1477  size_t n;
1478 
1479  //A name-list is represented as a uint32 containing its length followed
1480  //by a comma-separated list of zero or more names
1481  n = sizeof(uint32_t);
1482 
1483  //Loop through the list of names
1484  for(i = 0; i < nameListLen; i++)
1485  {
1486  //Names are separated by commas
1487  if(n != sizeof(uint32_t))
1488  {
1489  p[n++] = ',';
1490  }
1491 
1492  //A name must have a non-zero length and it must not contain a comma
1493  osStrcpy((char_t *) p + n, nameList[i]);
1494 
1495  //Update the length of the name list
1496  n += osStrlen(nameList[i]);
1497  }
1498 
1499  //The name list is preceded by a uint32 containing its length
1500  STORE32BE(n - sizeof(uint32_t), p);
1501 
1502  //Total number of bytes that have been written
1503  *written = n;
1504 
1505  //Successful processing
1506  return NO_ERROR;
1507 }
1508 
1509 
1510 /**
1511  * @brief Format a multiple precision integer
1512  * @param[in] value Pointer to a multiple precision integer
1513  * @param[out] p Output stream where to write the multiple precision integer
1514  * @param[out] written Total number of bytes that have been written
1515  * @return Error code
1516  **/
1517 
1518 error_t sshFormatMpint(const Mpi *value, uint8_t *p, size_t *written)
1519 {
1520  error_t error;
1521  size_t n;
1522 
1523  //Initialize status code
1524  error = NO_ERROR;
1525 
1526  //Retrieve the length of the multiple precision integer
1527  n = mpiGetBitLength(value);
1528 
1529  //The value zero must be stored as a string with zero bytes of data
1530  if(n != 0)
1531  {
1532  //If the most significant bit would be set for a positive number, the
1533  //number must be preceded by a zero byte (refer to RFC 4251, section 5)
1534  n = (n / 8) + 1;
1535  }
1536 
1537  //If the output parameter is NULL, then the function calculates the length
1538  //of the mpint representation without copying any data
1539  if(p != NULL)
1540  {
1541  //The value of the multiple precision integer is encoded MSB first.
1542  //Unnecessary leading bytes with the value 0 must not be included
1543  error = mpiExport(value, p + sizeof(uint32_t), n, MPI_FORMAT_BIG_ENDIAN);
1544 
1545  //Check status code
1546  if(!error)
1547  {
1548  //The integer is preceded by a uint32 containing its length
1549  STORE32BE(n, p);
1550  }
1551  }
1552 
1553  //Check status code
1554  if(!error)
1555  {
1556  //Total number of bytes that have been written
1557  *written = sizeof(uint32_t) + n;
1558  }
1559 
1560  //Return status code
1561  return error;
1562 }
1563 
1564 
1565 /**
1566  * @brief Convert a scalar to mpint representation
1567  * @param[in] value Pointer the integer
1568  * @param[in] length Length of the integer, in words
1569  * @param[out] p Output stream where to write the multiple precision integer
1570  * @param[out] written Total number of bytes that have been written
1571  * @return Error code
1572  **/
1573 
1575  uint8_t *p, size_t *written)
1576 {
1577 #if (SSH_ECDSA_SIGN_SUPPORT == ENABLED)
1578  error_t error;
1579  size_t n;
1580 
1581  //Initialize status code
1582  error = NO_ERROR;
1583 
1584  //Retrieve the length of the multiple precision integer
1586 
1587  //The value zero must be stored as a string with zero bytes of data
1588  if(n != 0)
1589  {
1590  //If the most significant bit would be set for a positive number, the
1591  //number must be preceded by a zero byte (refer to RFC 4251, section 5)
1592  n = (n / 8) + 1;
1593  }
1594 
1595  //If the output parameter is NULL, then the function calculates the length
1596  //of the mpint representation without copying any data
1597  if(p != NULL)
1598  {
1599  //The value of the multiple precision integer is encoded MSB first.
1600  //Unnecessary leading bytes with the value 0 must not be included
1601  error = ecScalarExport(value, length, p + sizeof(uint32_t), n,
1603 
1604  //Check status code
1605  if(!error)
1606  {
1607  //The integer is preceded by a uint32 containing its length
1608  STORE32BE(n, p);
1609  }
1610  }
1611 
1612  //Check status code
1613  if(!error)
1614  {
1615  //Total number of bytes that have been written
1616  *written = sizeof(uint32_t) + n;
1617  }
1618 
1619  //Return status code
1620  return error;
1621 #else
1622  //Not implemented
1623  return ERROR_NOT_IMPLEMENTED;
1624 #endif
1625 }
1626 
1627 /**
1628  * @brief Convert a binary string to mpint representation
1629  * @param[in] value Pointer to the binary string (MSB first encoded)
1630  * @param[out] length Length of the binary string, in bytes
1631  * @param[out] p Output stream where to write the mpint representation
1632  * @param[out] written Total number of bytes that have been written
1633  * @return Error code
1634  **/
1635 
1636 error_t sshConvertArrayToMpint(const uint8_t *value, size_t length, uint8_t *p,
1637  size_t *written)
1638 {
1639  size_t n;
1640 
1641  //Unnecessary leading bytes with the value 0 must not be included. The value
1642  //zero must be stored as a string with zero bytes of data (refer to RFC 4251,
1643  //section 5)
1644  while(length > 0 && value[0] == 0)
1645  {
1646  value++;
1647  length--;
1648  }
1649 
1650  //Check whether the most significant bit is set
1651  if(length > 0 && (value[0] & 0x80) != 0)
1652  {
1653  n = 1;
1654  }
1655  else
1656  {
1657  n = 0;
1658  }
1659 
1660  //The value of the multiple precision integer is encoded MSB first
1661  osMemmove(p + 4 + n, value, length);
1662 
1663  //If the most significant bit would be set for a positive number, the
1664  //number must be preceded by a zero byte
1665  if(n != 0)
1666  {
1667  p[4] = 0;
1668  }
1669 
1670  //Update the length of the data
1671  n += length;
1672 
1673  //The integer is preceded by a uint32 containing its length
1674  STORE32BE(n, p);
1675 
1676  //Total number of bytes that have been written
1677  *written = sizeof(uint32_t) + n;
1678 
1679  //Successful processing
1680  return NO_ERROR;
1681 }
1682 
1683 
1684 /**
1685  * @brief Compare a binary string against the supplied value
1686  * @param[in] string Pointer to the binary string
1687  * @param[in] value NULL-terminated string
1688  * @return Comparison result
1689  **/
1690 
1692 {
1693  bool_t res;
1694  size_t n;
1695 
1696  //Initialize flag
1697  res = FALSE;
1698 
1699  //Valid NULL-terminated string?
1700  if(value != NULL)
1701  {
1702  //Determine the length of the string
1703  n = osStrlen(value);
1704 
1705  //Check the length of the binary string
1706  if(string->value != NULL && string->length == n)
1707  {
1708  //Perform string comparison
1709  if(osStrncmp(string->value, value, n) == 0)
1710  {
1711  res = TRUE;
1712  }
1713  }
1714  }
1715 
1716  //Return comparison result
1717  return res;
1718 }
1719 
1720 
1721 /**
1722  * @brief Compare binary strings
1723  * @param[in] string1 Pointer to the first binary string
1724  * @param[in] string2 Pointer to the second binary string
1725  * @return Comparison result
1726  **/
1727 
1728 bool_t sshCompareStrings(const SshString *string1, const SshString *string2)
1729 {
1730  bool_t res;
1731 
1732  //Initialize flag
1733  res = FALSE;
1734 
1735  //Check the length of the binary strings
1736  if(string1->value != NULL && string2->value != NULL &&
1737  string1->length == string2->length)
1738  {
1739  //Perform string comparison
1740  if(osMemcmp(string1->value, string2->value, string2->length) == 0)
1741  {
1742  res = TRUE;
1743  }
1744  }
1745 
1746  //Return comparison result
1747  return res;
1748 }
1749 
1750 
1751 /**
1752  * @brief Compare algorithm names
1753  * @param[in] name1 Name of the first algorithm
1754  * @param[in] name2 Name of the second algorithm
1755  * @return Comparison result
1756  **/
1757 
1758 bool_t sshCompareAlgo(const char_t *name1, const char_t *name2)
1759 {
1760  bool_t res;
1761 
1762  //Initialize flag
1763  res = FALSE;
1764 
1765  //Valid NULL-terminated strings?
1766  if(name1 != NULL && name2 != NULL)
1767  {
1768  //Perform string comparison
1769  if(osStrcmp(name1, name2) == 0)
1770  {
1771  res = TRUE;
1772  }
1773  }
1774 
1775  //Return comparison result
1776  return res;
1777 }
1778 
1779 #endif
error_t socketSend(Socket *socket, const void *data, size_t length, size_t *written, uint_t flags)
Send data to a connected socket.
Definition: socket.c:1514
SSH channel management.
void sshUnregisterUserEvents(SshChannel *channel)
Unsubscribe previously registered events.
Definition: ssh_misc.c:666
#define SSH_MAX_CONN_CLOSE_CALLBACKS
Definition: ssh.h:220
int bool_t
Definition: compiler_port.h:63
void rsaFreePublicKey(RsaPublicKey *key)
Release an RSA public key.
Definition: rsa.c:113
SSH user authentication protocol.
@ SSH_CONN_STATE_USER_AUTH_REPLY
Definition: ssh.h:1086
@ SSH_CONN_STATE_OPEN
Definition: ssh.h:1088
@ SSH_CONN_STATE_KEX_KEM_REPLY
Definition: ssh.h:1074
error_t sshConvertScalarToMpint(const uint32_t *value, uint_t length, uint8_t *p, size_t *written)
Convert a scalar to mpint representation.
Definition: ssh_misc.c:1574
#define SECP521R1_CURVE
Definition: ec_curves.h:53
void sshUpdateChannelEvents(SshChannel *channel)
Update SSH channel related events.
Definition: ssh_channel.c:386
error_t ecScalarExport(const uint32_t *a, uint_t n, uint8_t *output, size_t length, EcScalarFormat format)
Integer to octet string conversion.
Definition: ec_misc.c:150
void sshFreeEncryptionEngine(SshEncryptionEngine *encryptionEngine)
Release encryption engine.
Arbitrary precision integer.
Definition: mpi.h:102
signed int int_t
Definition: compiler_port.h:56
error_t sshSendKexDhInit(SshConnection *connection)
Send SSH_MSG_KEX_DH_INIT message.
Definition: ssh_kex_dh.c:59
#define LOAD32BE(p)
Definition: cpu_endian.h:210
@ SSH_CONN_STATE_KEX_HYBRID_INIT
Definition: ssh.h:1075
Binary string.
Definition: ssh_types.h:67
Diffie-Hellman key exchange.
@ SSH_CONN_STATE_KEX_DH_GEX_REQUEST
Definition: ssh.h:1067
@ ERROR_NOT_IMPLEMENTED
Definition: error.h:66
@ SSH_CONN_STATE_SERVER_EXT_INFO_2
Definition: ssh.h:1081
@ SSH_CONN_STATE_KEX_RSA_SECRET
Definition: ssh.h:1063
ECDH key exchange.
#define SECP384R1_CURVE
Definition: ec_curves.h:52
uint8_t p
Definition: ndp.h:300
@ SSH_CONN_STATE_SERVICE_ACCEPT
Definition: ssh.h:1083
#define TRUE
Definition: os_port.h:50
#define SECP256R1_CURVE
Definition: ec_curves.h:51
SshConnection * sshOpenConnection(SshContext *context, Socket *socket)
Open a new SSH connection.
Definition: ssh_misc.c:68
void socketClose(Socket *socket)
Close an existing socket.
Definition: socket.c:2094
Event object.
uint_t ecScalarGetBitLength(const uint32_t *a, uint_t n)
Get the actual length in bits.
Definition: ec_misc.c:273
void ecdhFree(EcdhContext *context)
Release ECDH context.
Definition: ecdh.c:65
bool_t sshGetName(const SshNameList *nameList, uint_t index, SshString *name)
Get the element at specified index.
Definition: ssh_misc.c:1364
void kemInit(KemContext *context, const KemAlgo *kemAlgo)
Initialize KEM context.
Definition: kem.c:48
error_t sshParseString(const uint8_t *p, size_t length, SshString *string)
Parse a string.
Definition: ssh_misc.c:1178
SSH transport layer protocol.
#define osMemcmp(p1, p2, length)
Definition: os_port.h:156
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
size_t length
Definition: ssh_types.h:58
#define osStrcmp(s1, s2)
Definition: os_port.h:174
#define osStrlen(s)
Definition: os_port.h:168
SSH key file import functions.
error_t sshFormatEd448PublicKey(const EddsaPublicKey *publicKey, uint8_t *p, size_t *written)
Format an Ed448 public host key.
const uint8_t res[]
Pure post-quantum key exchange.
@ SSH_CONN_STATE_KEX_DH_GEX_GROUP
Definition: ssh.h:1068
void kemFree(KemContext *context)
Release KEM context.
Definition: kem.c:62
@ SSH_CONN_STATE_KEX_HYBRID_REPLY
Definition: ssh.h:1076
@ SSH_CONN_STATE_SERVER_EXT_INFO_1
Definition: ssh.h:1080
Structure describing socket events.
Definition: socket.h:433
bool_t sshCompareString(const SshString *string, const char_t *value)
Compare a binary string against the supplied value.
Definition: ssh_misc.c:1691
error_t sshFormatRsaPublicKey(const RsaPublicKey *publicKey, uint8_t *p, size_t *written)
Format an RSA public host key.
@ ERROR_WRONG_STATE
Definition: error.h:210
@ SSH_CONN_STATE_DISCONNECT
Definition: ssh.h:1089
error_t sshSendNewKeys(SshConnection *connection)
Send SSH_MSG_NEWKEYS message.
Definition: ssh_kex.c:204
error_t sshFormatBinaryString(const void *value, size_t valueLen, uint8_t *p, size_t *written)
Format a binary string.
Definition: ssh_misc.c:1446
Key material generation.
#define FALSE
Definition: os_port.h:46
RSA key exchange.
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:1636
const char_t * sshGetKeyFormatId(const SshString *publicKeyAlgo)
Get the key format identifier used by a given public key algorithm.
error_t sshSendKexEcdhInit(SshConnection *connection)
Send SSH_MSG_KEX_ECDH_INIT message.
Definition: ssh_kex_ecdh.c:58
DSA public key.
Definition: dsa.h:61
#define SshContext
Definition: ssh.h:892
#define osMemcpy(dest, src, length)
Definition: os_port.h:144
const char_t * keyFormatId
Key format identifier.
Definition: ssh.h:1170
DH GEX (Diffie-Hellman Group Exchange) key exchange.
const char_t * value
Definition: ssh_types.h:57
error_t
Error codes.
Definition: error.h:43
void ecInitPublicKey(EcPublicKey *key)
Initialize an EC public key.
Definition: ec.c:52
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
EdDSA public key.
Definition: eddsa.h:64
int_t socket(int_t family, int_t type, int_t protocol)
Create a socket that is bound to a specific transport service provider.
Definition: bsd_socket.c:65
@ SOCKET_EVENT_TX_READY
Definition: socket.h:175
@ SSH_OPERATION_MODE_SERVER
Definition: ssh.h:915
@ SSH_CONN_STATE_KEX_KEM_INIT
Definition: ssh.h:1073
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
@ SSH_OPERATION_MODE_CLIENT
Definition: ssh.h:914
const char_t * publicKey
Public key (PEM, SSH2 or OpenSSH format)
Definition: ssh.h:1171
const EcCurve * sshGetCurve(const SshString *keyFormatId, const SshString *curveName)
Get the elliptic curve that matches the specified key format identifier.
Definition: ssh_misc.c:1096
@ SSH_CONN_STATE_KEX_ECDH_INIT
Definition: ssh.h:1071
int_t sshSelectNextHostKey(SshConnection *connection)
Select the next acceptable host key.
Definition: ssh_misc.c:820
error_t sshImportDsaPublicKey(DsaPublicKey *publicKey, const char_t *input, size_t length)
Decode an SSH public key file containing a DSA public key.
Helper routines for ECC.
RSA public key.
Definition: rsa.h:57
error_t sshFormatEd25519PublicKey(const EddsaPublicKey *publicKey, uint8_t *p, size_t *written)
Format an Ed25519 public host key.
void dhFree(DhContext *context)
Release Diffie-Hellman context.
Definition: dh.c:71
Host key.
Definition: ssh.h:1169
error_t sshProcessConnectionEvents(SshContext *context, SshConnection *connection)
Connection event handler.
Definition: ssh_misc.c:375
void sshCloseConnection(SshConnection *connection)
Close SSH connection.
Definition: ssh_misc.c:174
@ SSH_CONN_STATE_KEX_ECDH_REPLY
Definition: ssh.h:1072
@ SSH_CONN_STATE_KEX_RSA_PUB_KEY
Definition: ssh.h:1062
@ SSH_CONN_STATE_CLIENT_ID
Definition: ssh.h:1058
size_t publicKeyLen
Length of the public key.
Definition: ssh.h:1172
error_t sshSendUserAuthSuccess(SshConnection *connection)
Send SSH_MSG_USERAUTH_SUCCESS message.
Definition: ssh_auth.c:171
SSH key formatting.
error_t mpiExport(const Mpi *a, uint8_t *output, size_t length, MpiFormat format)
Integer to octet string conversion.
Definition: mpi.c:811
error_t sshParseNameList(const uint8_t *p, size_t length, SshNameList *nameList)
Parse a comma-separated list of names.
Definition: ssh_misc.c:1253
#define TRACE_INFO(...)
Definition: debug.h:105
uint8_t length
Definition: tcp.h:375
#define SSH_MAX_HOST_KEYS
Definition: ssh.h:178
@ SSH_CONN_STATE_SERVER_NEW_KEYS
Definition: ssh.h:1078
String.
Definition: ssh_types.h:56
SSH key exchange.
error_t sshProcessChannelEvents(SshChannel *channel)
Channel event handler.
Definition: ssh_channel.c:232
uint_t sshGetUserEvents(SshChannel *channel)
Retrieve event flags for a specified channel.
Definition: ssh_misc.c:689
error_t sshSendExtInfo(SshConnection *connection)
Send SSH_MSG_EXT_INFO message.
error_t sshFormatDsaPublicKey(const DsaPublicKey *publicKey, uint8_t *p, size_t *written)
Format a DSA public host key.
error_t sshImportCertificate(const char_t *input, size_t inputLen, uint8_t *output, size_t *outputLen)
Import SSH certificate (OpenSSH format)
@ SSH_CONN_STATE_CLOSED
Definition: ssh.h:1057
error_t sshSendIdString(SshConnection *connection)
Send identification string.
Definition: ssh_transport.c:51
const char_t * value
Definition: ssh_types.h:79
@ ERROR_CONNECTION_CLOSING
Definition: error.h:78
uint_t mpiGetBitLength(const Mpi *a)
Get the actual length in bits.
Definition: mpi.c:255
@ SSH_CONN_STATE_USER_AUTH_SUCCESS
Definition: ssh.h:1087
error_t sshFormatMpint(const Mpi *value, uint8_t *p, size_t *written)
Format a multiple precision integer.
Definition: ssh_misc.c:1518
@ SSH_CONN_STATE_CLIENT_NEW_KEYS
Definition: ssh.h:1077
void sshNotifyEvent(SshContext *context)
Notify the SSH context that event is occurring.
Definition: ssh_misc.c:721
error_t sshSendKexDhGexRequest(SshConnection *connection)
Send SSH_MSG_KEX_DH_GEX_REQUEST message.
EC public key.
Definition: ec.h:421
void ecdhInit(EcdhContext *context)
Initialize ECDH context.
Definition: ecdh.c:49
@ ERROR_TIMEOUT
Definition: error.h:95
char char_t
Definition: compiler_port.h:55
const char_t * publicKeyAlgo
Public key algorithm to use during user authentication.
Definition: ssh.h:1177
#define sshFreeMem(p)
Definition: ssh.h:736
Post-quantum hybrid key exchange.
@ SSH_CONN_STATE_SERVER_KEX_INIT
Definition: ssh.h:1061
@ SSH_CONN_STATE_SERVER_ID
Definition: ssh.h:1059
@ SSH_CONN_STATE_KEX_DH_INIT
Definition: ssh.h:1065
@ SSH_CONN_STATE_CLIENT_EXT_INFO
Definition: ssh.h:1079
@ SOCKET_EVENT_RX_READY
Definition: socket.h:179
error_t sshSendServiceRequest(SshConnection *connection)
Send SSH_MSG_SERVICE_REQUEST message.
uint8_t n
@ EC_SCALAR_FORMAT_BIG_ENDIAN
Definition: ec_misc.h:51
void sshRegisterConnectionEvents(SshContext *context, SshConnection *connection, SocketEventDesc *eventDesc)
Register connection events.
Definition: ssh_misc.c:282
@ SSH_CONN_STATE_KEX_RSA_DONE
Definition: ssh.h:1064
@ SSH_CONN_STATE_SERVICE_REQUEST
Definition: ssh.h:1082
#define SshConnection
Definition: ssh.h:896
void osAcquireMutex(OsMutex *mutex)
Acquire ownership of the specified mutex object.
#define SSH_MAX_CONN_OPEN_CALLBACKS
Definition: ssh.h:213
void osReleaseMutex(OsMutex *mutex)
Release ownership of the specified mutex object.
SshHostKey * sshGetHostKey(SshConnection *connection)
Get the currently selected host key.
Definition: ssh_misc.c:734
@ SSH_CONN_STATE_USER_AUTH_REQUEST
Definition: ssh.h:1085
#define Socket
Definition: socket.h:36
@ SSH_CONN_STATE_CLIENT_KEX_INIT
Definition: ssh.h:1060
uint8_t value[]
Definition: tcp.h:376
@ SSH_CONN_STATE_KEX_DH_GEX_REPLY
Definition: ssh.h:1070
error_t sshImportEcdsaPublicKey(EcPublicKey *publicKey, const char_t *input, size_t length)
Decode an SSH public key file containing an ECDSA public key.
SSH certificate import functions.
SSH helper functions.
@ MPI_FORMAT_BIG_ENDIAN
Definition: mpi.h:93
SSH extension negotiation.
void sshRegisterUserEvents(SshChannel *channel, OsEvent *event, uint_t eventMask)
Subscribe to the specified channel events.
Definition: ssh_misc.c:631
size_t length
Definition: ssh_types.h:80
void eddsaFreePublicKey(EddsaPublicKey *key)
Release an EdDSA public key.
Definition: eddsa.c:63
@ ERROR_INVALID_SYNTAX
Definition: error.h:68
error_t sshFormatHostKey(SshConnection *connection, uint8_t *p, size_t *written)
Format host key structure.
Definition: ssh_misc.c:875
error_t sshSendKexHybridInit(SshConnection *connection)
Send SSH_MSG_KEX_HYBRID_INIT message.
@ SSH_CONN_STATE_KEX_DH_REPLY
Definition: ssh.h:1066
void osSetEvent(OsEvent *event)
Set the specified event object to the signaled state.
#define osStrncmp(s1, s2, length)
Definition: os_port.h:180
error_t sshReceivePacket(SshConnection *connection)
Receive SSH packet.
Definition: ssh_packet.c:178
SSH packet encryption/decryption.
error_t sshSendKexInit(SshConnection *connection)
Send SSH_MSG_KEXINIT message.
Definition: ssh_kex.c:60
int_t sshSelectHostKey(SshContext *context, const char_t *hostKeyAlgo)
Select a host key that matches then specified algorithm.
Definition: ssh_misc.c:769
@ SSH_CONN_STATE_KEX_DH_GEX_INIT
Definition: ssh.h:1069
error_t sshParseBinaryString(const uint8_t *p, size_t length, SshBinaryString *string)
Parse a binary string.
Definition: ssh_misc.c:1215
#define EcCurve
Definition: ec.h:346
error_t sshFormatString(const char_t *value, uint8_t *p, size_t *written)
Format a string.
Definition: ssh_misc.c:1410
void sshRegisterChannelEvents(SshChannel *channel, SocketEventDesc *eventDesc)
Register channel events.
Definition: ssh_channel.c:185
error_t sshImportRsaPublicKey(RsaPublicKey *publicKey, const char_t *input, size_t length)
Decode an SSH public key file containing an RSA public key.
Socket * socket
Handle to a socket to monitor.
Definition: socket.h:434
unsigned int uint_t
Definition: compiler_port.h:57
@ SSH_CHANNEL_STATE_CLOSED
Definition: ssh.h:1102
#define osMemset(p, value, length)
Definition: os_port.h:138
error_t sshSendKexKemInit(SshConnection *connection)
Send SSH_MSG_KEX_KEM_INIT message.
Definition: ssh_kex_kem.c:58
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.
void eddsaInitPublicKey(EddsaPublicKey *key)
Initialize an EdDSA public key.
Definition: eddsa.c:48
#define osStrcpy(s1, s2)
Definition: os_port.h:210
@ SSH_CHANNEL_STATE_UNUSED
Definition: ssh.h:1099
void dhInit(DhContext *context)
Initialize Diffie-Hellman context.
Definition: dh.c:54
void dsaFreePublicKey(DsaPublicKey *key)
Release a DSA public key.
Definition: dsa.c:119
#define STORE32BE(a, p)
Definition: cpu_endian.h:286
error_t sshSendUserAuthRequest(SshConnection *connection)
Send SSH_MSG_USERAUTH_REQUEST message.
Definition: ssh_auth.c:109
uint_t eventMask
Requested events.
Definition: socket.h:435
void dsaInitPublicKey(DsaPublicKey *key)
Initialize a DSA public key.
Definition: dsa.c:105
@ ERROR_INVALID_KEY
Definition: error.h:106
error_t sshFormatEcdsaPublicKey(const EcPublicKey *publicKey, uint8_t *p, size_t *written)
Format an ECDSA public host key.
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
#define osMemmove(dest, src, length)
Definition: os_port.h:150
void rsaInitPublicKey(RsaPublicKey *key)
Initialize an RSA public key.
Definition: rsa.c:100
error_t sshImportEd448PublicKey(EddsaPublicKey *publicKey, const char_t *input, size_t length)
Decode an SSH public key file containing an Ed448 public key.
#define SshChannel
Definition: ssh.h:900
void ecFreePublicKey(EcPublicKey *key)
Release an EC public key.
Definition: ec.c:68
bool_t sshCompareStrings(const SshString *string1, const SshString *string2)
Compare binary strings.
Definition: ssh_misc.c:1728
systime_t osGetSystemTime(void)
Retrieve system time.
error_t sshSendKexRsaPubKey(SshConnection *connection)
Send SSH_MSG_KEXRSA_PUBKEY message.
Definition: ssh_kex_rsa.c:61
error_t sshImportEd25519PublicKey(EddsaPublicKey *publicKey, const char_t *input, size_t length)
Decode an SSH public key file containing an Ed25519 public key.