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