ssh_key_import.c
Go to the documentation of this file.
1 /**
2  * @file ssh_key_import.c
3  * @brief SSH key file import 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.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_key_import.h"
37 #include "ssh/ssh_key_parse.h"
38 #include "ssh/ssh_key_decrypt.h"
39 #include "ssh/ssh_misc.h"
40 #include "encoding/base64.h"
41 #include "pkix/pem_import.h"
42 #include "ecc/ec_misc.h"
43 #include "debug.h"
44 
45 //Check SSH stack configuration
46 #if (SSH_SUPPORT == ENABLED)
47 
48 
49 /**
50  * @brief List of supported key types
51  **/
52 
53 static const SshKeyType sshKeyTypes[] =
54 {
55 #if (SSH_RSA_SIGN_SUPPORT == ENABLED)
56  {"ssh-rsa", X509_KEY_TYPE_RSA, NULL},
57 #endif
58 #if (SSH_DSA_SIGN_SUPPORT == ENABLED)
59  {"ssh-dss", X509_KEY_TYPE_DSA, NULL},
60 #endif
61 #if (SSH_ECDSA_SIGN_SUPPORT == ENABLED && SSH_NISTP256_SUPPORT == ENABLED)
62  {"ecdsa-sha2-nistp256", X509_KEY_TYPE_EC, "secp256r1"},
63 #endif
64 #if (SSH_ECDSA_SIGN_SUPPORT == ENABLED && SSH_NISTP384_SUPPORT == ENABLED)
65  {"ecdsa-sha2-nistp384", X509_KEY_TYPE_EC, "secp384r1"},
66 #endif
67 #if (SSH_ECDSA_SIGN_SUPPORT == ENABLED && SSH_NISTP521_SUPPORT == ENABLED)
68  {"ecdsa-sha2-nistp521", X509_KEY_TYPE_EC, "secp521r1"},
69 #endif
70 #if (SSH_ED25519_SIGN_SUPPORT == ENABLED)
71  {"ssh-ed25519", X509_KEY_TYPE_ED25519, NULL},
72 #endif
73 #if (SSH_ED448_SIGN_SUPPORT == ENABLED)
74  {"ssh-ed448", X509_KEY_TYPE_ED448, NULL},
75 #endif
76 };
77 
78 
79 /**
80  * @brief Decode an SSH public key file containing an RSA public key
81  * @param[out] publicKey RSA public key resulting from the parsing process
82  * @param[in] input Pointer to the SSH public key file
83  * @param[in] length Length of the SSH public key file
84  * @return Error code
85  **/
86 
88  size_t length)
89 {
90 #if (SSH_RSA_SIGN_SUPPORT == ENABLED)
91  error_t error;
92  size_t n;
93  uint8_t *buffer;
94  SshRsaHostKey hostKey;
95 
96  //Check parameters
97  if(input == NULL && length != 0)
99  if(publicKey == NULL)
101 
102  //Retrieve the length of the public key structure
103  error = sshDecodePublicKeyFile(input, length, NULL, &n);
104 
105  //Check status code
106  if(!error)
107  {
108  //Allocate a memory buffer to hold the public key structure
109  buffer = sshAllocMem(n);
110 
111  //Successful memory allocation?
112  if(buffer != NULL)
113  {
114  //Decode the content of the public key file (SSH2 or OpenSSH format)
115  error = sshDecodePublicKeyFile(input, length, buffer, &n);
116 
117  //Check status code
118  if(!error)
119  {
120  //Parse RSA host key structure
121  error = sshParseRsaHostKey(buffer, n, &hostKey);
122  }
123 
124  //Check status code
125  if(!error)
126  {
127  //Import RSA public key
128  error = sshImportRsaHostKey(publicKey, &hostKey);
129  }
130 
131  //Release previously allocated memory
132  sshFreeMem(buffer);
133  }
134  else
135  {
136  //Failed to allocate memory
137  error = ERROR_OUT_OF_MEMORY;
138  }
139  }
140  else
141  {
142  //Decode the content of the public key file (PEM format)
143  error = pemImportRsaPublicKey(publicKey, input, length);
144  }
145 
146  //Any error to report?
147  if(error)
148  {
149  //Clean up side effects
150  rsaFreePublicKey(publicKey);
151  }
152 
153  //Return status code
154  return error;
155 #else
156  //Not implemented
157  return ERROR_NOT_IMPLEMENTED;
158 #endif
159 }
160 
161 
162 /**
163  * @brief Decode an SSH public key file containing a DSA public key
164  * @param[out] publicKey DSA public key resulting from the parsing process
165  * @param[in] input Pointer to the SSH public key file
166  * @param[in] length Length of the SSH public key file
167  * @return Error code
168  **/
169 
171  size_t length)
172 {
173 #if (SSH_DSA_SIGN_SUPPORT == ENABLED)
174  error_t error;
175  size_t n;
176  uint8_t *buffer;
177  SshDsaHostKey hostKey;
178 
179  //Check parameters
180  if(input == NULL && length != 0)
182  if(publicKey == NULL)
184 
185  //Retrieve the length of the public key structure
186  error = sshDecodePublicKeyFile(input, length, NULL, &n);
187 
188  //Check status code
189  if(!error)
190  {
191  //Allocate a memory buffer to hold the public key structure
192  buffer = sshAllocMem(n);
193 
194  //Successful memory allocation?
195  if(buffer != NULL)
196  {
197  //Decode the content of the public key file (SSH2 or OpenSSH format)
198  error = sshDecodePublicKeyFile(input, length, buffer, &n);
199 
200  //Check status code
201  if(!error)
202  {
203  //Parse DSA host key structure
204  error = sshParseDsaHostKey(buffer, n, &hostKey);
205  }
206 
207  //Check status code
208  if(!error)
209  {
210  //Import DSA public key
211  error = sshImportDsaHostKey(publicKey, &hostKey);
212  }
213 
214  //Release previously allocated memory
215  sshFreeMem(buffer);
216  }
217  else
218  {
219  //Failed to allocate memory
220  error = ERROR_OUT_OF_MEMORY;
221  }
222  }
223  else
224  {
225  //Decode the content of the public key file (PEM format)
226  error = pemImportDsaPublicKey(publicKey, input, length);
227  }
228 
229  //Any error to report?
230  if(error)
231  {
232  //Clean up side effects
233  dsaFreePublicKey(publicKey);
234  }
235 
236  //Return status code
237  return error;
238 #else
239  //Not implemented
240  return ERROR_NOT_IMPLEMENTED;
241 #endif
242 }
243 
244 
245 /**
246  * @brief Decode an SSH public key file containing an ECDSA public key
247  * @param[out] publicKey ECDSA public key resulting from the parsing process
248  * @param[in] input Pointer to the SSH public key file
249  * @param[in] length Length of the SSH public key file
250  * @return Error code
251  **/
252 
254  size_t length)
255 {
256 #if (SSH_ECDSA_SIGN_SUPPORT == ENABLED)
257  error_t error;
258  size_t n;
259  uint8_t *buffer;
260  SshEcdsaHostKey hostKey;
261 
262  //Check parameters
263  if(input == NULL && length != 0)
265  if(publicKey == NULL)
267 
268  //Retrieve the length of the public key structure
269  error = sshDecodePublicKeyFile(input, length, NULL, &n);
270 
271  //Check status code
272  if(!error)
273  {
274  //Allocate a memory buffer to hold the public key structure
275  buffer = sshAllocMem(n);
276 
277  //Successful memory allocation?
278  if(buffer != NULL)
279  {
280  //Decode the content of the public key file (SSH2 or OpenSSH format)
281  error = sshDecodePublicKeyFile(input, length, buffer, &n);
282 
283  //Check status code
284  if(!error)
285  {
286  //Parse ECDSA host key structure
287  error = sshParseEcdsaHostKey(buffer, n, &hostKey);
288  }
289 
290  //Check status code
291  if(!error)
292  {
293  //Import ECDSA public key
294  error = sshImportEcdsaHostKey(publicKey, &hostKey);
295  }
296 
297  //Release previously allocated memory
298  sshFreeMem(buffer);
299  }
300  else
301  {
302  //Failed to allocate memory
303  error = ERROR_OUT_OF_MEMORY;
304  }
305  }
306  else
307  {
308  //Decode the content of the public key file (PEM format)
309  error = pemImportEcPublicKey(publicKey, input, length);
310  }
311 
312  //Any error to report?
313  if(error)
314  {
315  //Clean up side effects
316  ecFreePublicKey(publicKey);
317  }
318 
319  //Return status code
320  return error;
321 #else
322  //Not implemented
323  return ERROR_NOT_IMPLEMENTED;
324 #endif
325 }
326 
327 
328 /**
329  * @brief Decode an SSH public key file containing an Ed25519 public key
330  * @param[out] publicKey Ed25519 public key resulting from the parsing process
331  * @param[in] input Pointer to the SSH public key file
332  * @param[in] length Length of the SSH public key file
333  * @return Error code
334  **/
335 
337  const char_t *input, size_t length)
338 {
339 #if (SSH_ED25519_SIGN_SUPPORT == ENABLED)
340  error_t error;
341  size_t n;
342  uint8_t *buffer;
343  SshEddsaHostKey hostKey;
344 
345  //Check parameters
346  if(input == NULL && length != 0)
348  if(publicKey == NULL)
350 
351  //Retrieve the length of the public key structure
352  error = sshDecodePublicKeyFile(input, length, NULL, &n);
353 
354  //Check status code
355  if(!error)
356  {
357  //Allocate a memory buffer to hold the public key structure
358  buffer = sshAllocMem(n);
359 
360  //Successful memory allocation?
361  if(buffer != NULL)
362  {
363  //Decode the content of the public key file (SSH2 or OpenSSH format)
364  error = sshDecodePublicKeyFile(input, length, buffer, &n);
365 
366  //Check status code
367  if(!error)
368  {
369  //Parse Ed25519 host key structure
370  error = sshParseEd25519HostKey(buffer, n, &hostKey);
371  }
372 
373  //Check status code
374  if(!error)
375  {
376  //Import Ed25519 public key
377  error = eddsaImportPublicKey(publicKey, ED25519_CURVE,
378  hostKey.q.value, hostKey.q.length);
379  }
380 
381  //Release previously allocated memory
382  sshFreeMem(buffer);
383  }
384  else
385  {
386  //Failed to allocate memory
387  error = ERROR_OUT_OF_MEMORY;
388  }
389  }
390  else
391  {
392  //Decode the content of the public key file (PEM format)
393  error = pemImportEddsaPublicKey(publicKey, input, length);
394  }
395 
396  //Any error to report?
397  if(error)
398  {
399  //Clean up side effects
400  eddsaFreePublicKey(publicKey);
401  }
402 
403  //Return status code
404  return error;
405 #else
406  //Not implemented
407  return ERROR_NOT_IMPLEMENTED;
408 #endif
409 }
410 
411 
412 /**
413  * @brief Decode an SSH public key file containing an Ed448 public key
414  * @param[out] publicKey Ed448 public key resulting from the parsing process
415  * @param[in] input Pointer to the SSH public key file
416  * @param[in] length Length of the SSH public key file
417  * @return Error code
418  **/
419 
421  const char_t *input, size_t length)
422 {
423 #if (SSH_ED448_SIGN_SUPPORT == ENABLED)
424  error_t error;
425  size_t n;
426  uint8_t *buffer;
427  SshEddsaHostKey hostKey;
428 
429  //Check parameters
430  if(input == NULL && length != 0)
432  if(publicKey == NULL)
434 
435  //Retrieve the length of the public key structure
436  error = sshDecodePublicKeyFile(input, length, NULL, &n);
437 
438  //Check status code
439  if(!error)
440  {
441  //Allocate a memory buffer to hold the public key structure
442  buffer = sshAllocMem(n);
443 
444  //Successful memory allocation?
445  if(buffer != NULL)
446  {
447  //Decode the content of the public key file (SSH2 or OpenSSH format)
448  error = sshDecodePublicKeyFile(input, length, buffer, &n);
449 
450  //Check status code
451  if(!error)
452  {
453  //Parse Ed448 host key structure
454  error = sshParseEd448HostKey(buffer, n, &hostKey);
455  }
456 
457  //Check status code
458  if(!error)
459  {
460  //Import Ed448 public key
461  error = eddsaImportPublicKey(publicKey, ED448_CURVE,
462  hostKey.q.value, hostKey.q.length);
463  }
464 
465  //Release previously allocated memory
466  sshFreeMem(buffer);
467  }
468  else
469  {
470  //Failed to allocate memory
471  error = ERROR_OUT_OF_MEMORY;
472  }
473  }
474  else
475  {
476  //Decode the content of the public key file (PEM format)
477  error = pemImportEddsaPublicKey(publicKey, input, length);
478  }
479 
480  //Any error to report?
481  if(error)
482  {
483  //Clean up side effects
484  eddsaFreePublicKey(publicKey);
485  }
486 
487  //Return status code
488  return error;
489 #else
490  //Not implemented
491  return ERROR_NOT_IMPLEMENTED;
492 #endif
493 }
494 
495 
496 /**
497  * @brief Decode an SSH private key file containing an RSA private key
498  * @param[out] privateKey RSA private key resulting from the parsing process
499  * @param[in] input Pointer to the SSH private key file
500  * @param[in] length Length of the SSH private key file
501  * @param[in] password NULL-terminated string containing the password. This
502  * parameter is required if the private key is encrypted
503  * @return Error code
504  **/
505 
507  size_t length, const char_t *password)
508 {
509 #if (SSH_RSA_SIGN_SUPPORT == ENABLED)
510  error_t error;
511  size_t n;
512  uint8_t *data;
513  uint8_t *buffer;
514  Mpi t;
515  SshPrivateKeyHeader privateKeyHeader;
516  SshRsaPrivateKey privateKeyInfo;
517 
518  //Check parameters
519  if(input == NULL && length != 0)
521  if(privateKey == NULL)
523 
524  //Retrieve the length of the private key structure
525  error = sshDecodeOpenSshPrivateKeyFile(input, length, NULL, &n);
526 
527  //Check status code
528  if(!error)
529  {
530  //Allocate a memory buffer to hold the private key structure
531  buffer = sshAllocMem(n);
532 
533  //Successful memory allocation?
534  if(buffer != NULL)
535  {
536  //Initialize multiple precision integer
537  mpiInit(&t);
538 
539  //Decode the content of the private key file (OpenSSH format)
540  error = sshDecodeOpenSshPrivateKeyFile(input, length, buffer, &n);
541 
542  //Check status code
543  if(!error)
544  {
545  //Parse private key header
546  error = sshParseOpenSshPrivateKeyHeader(buffer, n,
547  &privateKeyHeader);
548  }
549 
550  //Check status code
551  if(!error)
552  {
553  //Point to the encrypted data
554  data = (uint8_t *) privateKeyHeader.encrypted.value;
555  n = privateKeyHeader.encrypted.length;
556 
557  //Perform decryption operation
558  error = sshDecryptOpenSshPrivateKey(&privateKeyHeader, password,
559  data, data, n);
560  }
561 
562  //Check status code
563  if(!error)
564  {
565  //Parse RSA private key blob
566  error = sshParseOpenSshRsaPrivateKey(data, n, &privateKeyInfo);
567  }
568 
569  //Check status code
570  if(!error)
571  {
572  //Import RSA modulus
573  error = mpiImport(&privateKey->n, privateKeyInfo.n.value,
574  privateKeyInfo.n.length, MPI_FORMAT_BIG_ENDIAN);
575  }
576 
577  //Check status code
578  if(!error)
579  {
580  //Import RSA public exponent
581  error = mpiImport(&privateKey->e, privateKeyInfo.e.value,
582  privateKeyInfo.e.length, MPI_FORMAT_BIG_ENDIAN);
583  }
584 
585  //Check status code
586  if(!error)
587  {
588  //Import RSA private exponent
589  error = mpiImport(&privateKey->d, privateKeyInfo.d.value,
590  privateKeyInfo.d.length, MPI_FORMAT_BIG_ENDIAN);
591  }
592 
593  //Check status code
594  if(!error)
595  {
596  //Import RSA first factor
597  error = mpiImport(&privateKey->p, privateKeyInfo.p.value,
598  privateKeyInfo.p.length, MPI_FORMAT_BIG_ENDIAN);
599  }
600 
601  //Check status code
602  if(!error)
603  {
604  //Import RSA second factor
605  error = mpiImport(&privateKey->q, privateKeyInfo.q.value,
606  privateKeyInfo.q.length, MPI_FORMAT_BIG_ENDIAN);
607  }
608 
609  //Check status code
610  if(!error)
611  {
612  //Import RSA CRT coefficient
613  error = mpiImport(&privateKey->qinv, privateKeyInfo.qinv.value,
614  privateKeyInfo.qinv.length, MPI_FORMAT_BIG_ENDIAN);
615  }
616 
617  //Check status code
618  if(!error)
619  {
620  //Compute t = p - 1
621  error = mpiSubInt(&t, &privateKey->p, 1);
622  }
623 
624  //Check status code
625  if(!error)
626  {
627  //Compute first factor's CRT exponent
628  error = mpiMod(&privateKey->dp, &privateKey->d, &t);
629  }
630 
631  //Check status code
632  if(!error)
633  {
634  //Compute t = q - 1
635  error = mpiSubInt(&t, &privateKey->q, 1);
636  }
637 
638  //Check status code
639  if(!error)
640  {
641  //Compute second factor's CRT exponent
642  error = mpiMod(&privateKey->dq, &privateKey->d, &t);
643  }
644 
645  //Release multiple precision integers
646  mpiFree(&t);
647  //Release previously allocated memory
648  sshFreeMem(buffer);
649  }
650  else
651  {
652  //Failed to allocate memory
653  error = ERROR_OUT_OF_MEMORY;
654  }
655  }
656  else
657  {
658  //Decode the content of the private key file (PEM format)
659  error = pemImportRsaPrivateKey(privateKey, input, length, password);
660  }
661 
662  //Any error to report?
663  if(error)
664  {
665  //Clean up side effects
666  rsaFreePrivateKey(privateKey);
667  }
668 
669  //Return status code
670  return error;
671 #else
672  //Not implemented
673  return ERROR_NOT_IMPLEMENTED;
674 #endif
675 }
676 
677 
678 /**
679  * @brief Decode an SSH private key file containing a DSA private key
680  * @param[out] privateKey DSA private key resulting from the parsing process
681  * @param[in] input Pointer to the SSH private key file
682  * @param[in] length Length of the SSH private key file
683  * @param[in] password NULL-terminated string containing the password. This
684  * parameter is required if the private key is encrypted
685  * @return Error code
686  **/
687 
689  size_t length, const char_t *password)
690 {
691 #if (SSH_DSA_SIGN_SUPPORT == ENABLED)
692  error_t error;
693  size_t n;
694  uint8_t *data;
695  uint8_t *buffer;
696  SshPrivateKeyHeader privateKeyHeader;
697  SshDsaPrivateKey privateKeyInfo;
698 
699  //Check parameters
700  if(input == NULL && length != 0)
702  if(privateKey == NULL)
704 
705  //Retrieve the length of the private key structure
706  error = sshDecodeOpenSshPrivateKeyFile(input, length, NULL, &n);
707 
708  //Check status code
709  if(!error)
710  {
711  //Allocate a memory buffer to hold the private key structure
712  buffer = sshAllocMem(n);
713 
714  //Successful memory allocation?
715  if(buffer != NULL)
716  {
717  //Decode the content of the private key file (OpenSSH format)
718  error = sshDecodeOpenSshPrivateKeyFile(input, length, buffer, &n);
719 
720  //Check status code
721  if(!error)
722  {
723  //Parse private key header
724  error = sshParseOpenSshPrivateKeyHeader(buffer, n,
725  &privateKeyHeader);
726  }
727 
728  //Check status code
729  if(!error)
730  {
731  //Point to the encrypted data
732  data = (uint8_t *) privateKeyHeader.encrypted.value;
733  n = privateKeyHeader.encrypted.length;
734 
735  //Perform decryption operation
736  error = sshDecryptOpenSshPrivateKey(&privateKeyHeader, password,
737  data, data, n);
738  }
739 
740  //Check status code
741  if(!error)
742  {
743  //Parse DSA private key blob
744  error = sshParseOpenSshDsaPrivateKey(data, n, &privateKeyInfo);
745  }
746 
747  //Check status code
748  if(!error)
749  {
750  //Import DSA prime modulus
751  error = mpiImport(&privateKey->params.p, privateKeyInfo.p.value,
752  privateKeyInfo.p.length, MPI_FORMAT_BIG_ENDIAN);
753  }
754 
755  //Check status code
756  if(!error)
757  {
758  //Import DSA group order
759  error = mpiImport(&privateKey->params.q, privateKeyInfo.q.value,
760  privateKeyInfo.q.length, MPI_FORMAT_BIG_ENDIAN);
761  }
762 
763  //Check status code
764  if(!error)
765  {
766  //Import DSA group generator
767  error = mpiImport(&privateKey->params.g, privateKeyInfo.g.value,
768  privateKeyInfo.g.length, MPI_FORMAT_BIG_ENDIAN);
769  }
770 
771  //Check status code
772  if(!error)
773  {
774  //Import DSA private key value
775  error = mpiImport(&privateKey->x, privateKeyInfo.x.value,
776  privateKeyInfo.x.length, MPI_FORMAT_BIG_ENDIAN);
777  }
778 
779  //Check status code
780  if(!error)
781  {
782  //Import DSA public key value
783  error = mpiImport(&privateKey->y, privateKeyInfo.y.value,
784  privateKeyInfo.y.length, MPI_FORMAT_BIG_ENDIAN);
785  }
786 
787  //Release previously allocated memory
788  sshFreeMem(buffer);
789  }
790  else
791  {
792  //Failed to allocate memory
793  error = ERROR_OUT_OF_MEMORY;
794  }
795  }
796  else
797  {
798  //Decode the content of the private key file (PEM format)
799  error = pemImportDsaPrivateKey(privateKey, input, length, password);
800  }
801 
802  //Any error to report?
803  if(error)
804  {
805  //Clean up side effects
806  dsaFreePrivateKey(privateKey);
807  }
808 
809  //Return status code
810  return error;
811 #else
812  //Not implemented
813  return ERROR_NOT_IMPLEMENTED;
814 #endif
815 }
816 
817 
818 /**
819  * @brief Decode an SSH private key file containing an ECDSA private key
820  * @param[out] privateKey ECDSA private key resulting from the parsing process
821  * @param[in] input Pointer to the SSH private key file
822  * @param[in] length Length of the SSH private key file
823  * @param[in] password NULL-terminated string containing the password. This
824  * parameter is required if the private key is encrypted
825  * @return Error code
826  **/
827 
829  size_t length, const char_t *password)
830 {
831 #if (SSH_ECDSA_SIGN_SUPPORT == ENABLED)
832  error_t error;
833  size_t n;
834  uint8_t *data;
835  uint8_t *buffer;
836  SshPrivateKeyHeader privateKeyHeader;
837  SshEcdsaPrivateKey privateKeyInfo;
838  const EcCurve *curve;
839 
840  //Check parameters
841  if(input == NULL && length != 0)
843  if(privateKey == NULL)
845 
846  //Retrieve the length of the private key structure
847  error = sshDecodeOpenSshPrivateKeyFile(input, length, NULL, &n);
848 
849  //Check status code
850  if(!error)
851  {
852  //Allocate a memory buffer to hold the private key structure
853  buffer = sshAllocMem(n);
854 
855  //Successful memory allocation?
856  if(buffer != NULL)
857  {
858  //Decode the content of the private key file (OpenSSH format)
859  error = sshDecodeOpenSshPrivateKeyFile(input, length, buffer, &n);
860 
861  //Check status code
862  if(!error)
863  {
864  //Parse private key header
865  error = sshParseOpenSshPrivateKeyHeader(buffer, n,
866  &privateKeyHeader);
867  }
868 
869  //Check status code
870  if(!error)
871  {
872  //Point to the encrypted data
873  data = (uint8_t *) privateKeyHeader.encrypted.value;
874  n = privateKeyHeader.encrypted.length;
875 
876  //Perform decryption operation
877  error = sshDecryptOpenSshPrivateKey(&privateKeyHeader, password,
878  data, data, n);
879  }
880 
881  //Check status code
882  if(!error)
883  {
884  //Parse ECDSA private key blob
885  error = sshParseOpenSshEcdsaPrivateKey(data, n, &privateKeyInfo);
886  }
887 
888  //Check status code
889  if(!error)
890  {
891  //Retrieve the elliptic curve that matches the specified key format
892  //identifier
893  curve = sshGetCurve(&privateKeyInfo.keyFormatId,
894  &privateKeyInfo.curveName);
895 
896  //Make sure the key format identifier is acceptable
897  if(curve != NULL)
898  {
899  //Import EC private key
900  error = ecImportPrivateKey(privateKey, curve,
901  privateKeyInfo.d.value, privateKeyInfo.d.length);
902 
903  //Check status code
904  if(!error)
905  {
906  //Import EC public key
907  error = ecImportPublicKey(&privateKey->q, curve,
908  privateKeyInfo.q.value, privateKeyInfo.q.length,
910  }
911  }
912  else
913  {
914  //Report an error
915  error = ERROR_WRONG_IDENTIFIER;
916  }
917  }
918 
919  //Release previously allocated memory
920  sshFreeMem(buffer);
921  }
922  else
923  {
924  //Failed to allocate memory
925  error = ERROR_OUT_OF_MEMORY;
926  }
927  }
928  else
929  {
930  //Decode the content of the private key file (PEM format)
931  error = pemImportEcPrivateKey(privateKey, input, length, password);
932  }
933 
934  //Any error to report?
935  if(error)
936  {
937  //Clean up side effects
938  ecFreePrivateKey(privateKey);
939  }
940 
941  //Return status code
942  return error;
943 #else
944  //Not implemented
945  return ERROR_NOT_IMPLEMENTED;
946 #endif
947 }
948 
949 
950 /**
951  * @brief Decode an SSH private key file containing an Ed25519 private key
952  * @param[out] privateKey Ed25519 private key resulting from the parsing process
953  * @param[in] input Pointer to the SSH private key file
954  * @param[in] length Length of the SSH private key file
955  * @param[in] password NULL-terminated string containing the password. This
956  * parameter is required if the private key is encrypted
957  * @return Error code
958  **/
959 
961  const char_t *input, size_t length, const char_t *password)
962 {
963 #if (SSH_ED25519_SIGN_SUPPORT == ENABLED)
964  error_t error;
965  size_t n;
966  uint8_t *data;
967  uint8_t *buffer;
968  SshPrivateKeyHeader privateKeyHeader;
969  SshEddsaPrivateKey privateKeyInfo;
970 
971  //Check parameters
972  if(input == NULL && length != 0)
974  if(privateKey == NULL)
976 
977  //Retrieve the length of the private key structure
978  error = sshDecodeOpenSshPrivateKeyFile(input, length, NULL, &n);
979 
980  //Check status code
981  if(!error)
982  {
983  //Allocate a memory buffer to hold the private key structure
984  buffer = sshAllocMem(n);
985 
986  //Successful memory allocation?
987  if(buffer != NULL)
988  {
989  //Decode the content of the private key file (OpenSSH format)
990  error = sshDecodeOpenSshPrivateKeyFile(input, length, buffer, &n);
991 
992  //Check status code
993  if(!error)
994  {
995  //Parse private key header
996  error = sshParseOpenSshPrivateKeyHeader(buffer, n,
997  &privateKeyHeader);
998  }
999 
1000  //Check status code
1001  if(!error)
1002  {
1003  //Point to the encrypted data
1004  data = (uint8_t *) privateKeyHeader.encrypted.value;
1005  n = privateKeyHeader.encrypted.length;
1006 
1007  //Perform decryption operation
1008  error = sshDecryptOpenSshPrivateKey(&privateKeyHeader, password,
1009  data, data, n);
1010  }
1011 
1012  //Check status code
1013  if(!error)
1014  {
1015  //Parse Ed25519 private key blob
1016  error = sshParseOpenSshEd25519PrivateKey(data, n, &privateKeyInfo);
1017  }
1018 
1019  //Check status code
1020  if(!error)
1021  {
1022  //Import Ed25519 private key
1023  error = eddsaImportPrivateKey(privateKey, ED25519_CURVE,
1024  privateKeyInfo.d.value, ED25519_PRIVATE_KEY_LEN);
1025 
1026  //Check status code
1027  if(!error)
1028  {
1029  //Import Ed25519 public key
1030  error = eddsaImportPublicKey(&privateKey->q, ED25519_CURVE,
1031  privateKeyInfo.q.value, privateKeyInfo.q.length);
1032  }
1033  }
1034 
1035  //Release previously allocated memory
1036  sshFreeMem(buffer);
1037  }
1038  else
1039  {
1040  //Failed to allocate memory
1041  error = ERROR_OUT_OF_MEMORY;
1042  }
1043  }
1044  else
1045  {
1046  //Decode the content of the private key file (PEM format)
1047  error = pemImportEddsaPrivateKey(privateKey, input, length, password);
1048  }
1049 
1050  //Any error to report?
1051  if(error)
1052  {
1053  //Clean up side effects
1054  eddsaFreePrivateKey(privateKey);
1055  }
1056 
1057  //Return status code
1058  return error;
1059 #else
1060  //Not implemented
1061  return ERROR_NOT_IMPLEMENTED;
1062 #endif
1063 }
1064 
1065 
1066 /**
1067  * @brief Decode an SSH private key file containing an Ed448 private key
1068  * @param[out] privateKey Ed448 private key resulting from the parsing process
1069  * @param[in] input Pointer to the SSH private key file
1070  * @param[in] length Length of the SSH private key file
1071  * @param[in] password NULL-terminated string containing the password. This
1072  * parameter is required if the private key is encrypted
1073  * @return Error code
1074  **/
1075 
1077  const char_t *input, size_t length, const char_t *password)
1078 {
1079 #if (SSH_ED448_SIGN_SUPPORT == ENABLED)
1080  error_t error;
1081  size_t n;
1082  uint8_t *data;
1083  uint8_t *buffer;
1084  SshPrivateKeyHeader privateKeyHeader;
1085  SshEddsaPrivateKey privateKeyInfo;
1086 
1087  //Check parameters
1088  if(input == NULL && length != 0)
1089  return ERROR_INVALID_PARAMETER;
1090  if(privateKey == NULL)
1091  return ERROR_INVALID_PARAMETER;
1092 
1093  //Retrieve the length of the private key structure
1094  error = sshDecodeOpenSshPrivateKeyFile(input, length, NULL, &n);
1095 
1096  //Check status code
1097  if(!error)
1098  {
1099  //Allocate a memory buffer to hold the private key structure
1100  buffer = sshAllocMem(n);
1101 
1102  //Successful memory allocation?
1103  if(buffer != NULL)
1104  {
1105  //Decode the content of the private key file (OpenSSH format)
1106  error = sshDecodeOpenSshPrivateKeyFile(input, length, buffer, &n);
1107 
1108  //Check status code
1109  if(!error)
1110  {
1111  //Parse private key header
1112  error = sshParseOpenSshPrivateKeyHeader(buffer, n,
1113  &privateKeyHeader);
1114  }
1115 
1116  //Check status code
1117  if(!error)
1118  {
1119  //Point to the encrypted data
1120  data = (uint8_t *) privateKeyHeader.encrypted.value;
1121  n = privateKeyHeader.encrypted.length;
1122 
1123  //Perform decryption operation
1124  error = sshDecryptOpenSshPrivateKey(&privateKeyHeader, password,
1125  data, data, n);
1126  }
1127 
1128  //Check status code
1129  if(!error)
1130  {
1131  //Parse Ed448 private key blob
1132  error = sshParseOpenSshEd448PrivateKey(data, n, &privateKeyInfo);
1133  }
1134 
1135  //Check status code
1136  if(!error)
1137  {
1138  //Import Ed448 private key
1139  error = eddsaImportPrivateKey(privateKey, ED448_CURVE,
1140  privateKeyInfo.d.value, ED448_PRIVATE_KEY_LEN);
1141 
1142  //Check status code
1143  if(!error)
1144  {
1145  //Import Ed448 public key
1146  error = eddsaImportPublicKey(&privateKey->q, ED448_CURVE,
1147  privateKeyInfo.q.value, privateKeyInfo.q.length);
1148  }
1149  }
1150 
1151  //Release previously allocated memory
1152  sshFreeMem(buffer);
1153  }
1154  else
1155  {
1156  //Failed to allocate memory
1157  error = ERROR_OUT_OF_MEMORY;
1158  }
1159  }
1160  else
1161  {
1162  //Decode the content of the private key file (PEM format)
1163  error = pemImportEddsaPrivateKey(privateKey, input, length, password);
1164  }
1165 
1166  //Any error to report?
1167  if(error)
1168  {
1169  //Clean up side effects
1170  eddsaFreePrivateKey(privateKey);
1171  }
1172 
1173  //Return status code
1174  return error;
1175 #else
1176  //Not implemented
1177  return ERROR_NOT_IMPLEMENTED;
1178 #endif
1179 }
1180 
1181 
1182 /**
1183  * @brief Import an RSA host key
1184  * @param[out] publicKey Pointer to the RSA public key
1185  * @param[in] hostKey Pointer to the host key structure
1186  * @return Error code
1187  **/
1188 
1190  const SshRsaHostKey *hostKey)
1191 {
1192 #if (SSH_RSA_SIGN_SUPPORT == ENABLED)
1193  error_t error;
1194  uint_t k;
1195 
1196  //Import RSA public exponent
1197  error = mpiImport(&publicKey->e, hostKey->e.value, hostKey->e.length,
1199  //Any error to report?
1200  if(error)
1201  return error;
1202 
1203  //Import RSA modulus
1204  error = mpiImport(&publicKey->n, hostKey->n.value, hostKey->n.length,
1206  //Any error to report?
1207  if(error)
1208  return error;
1209 
1210  //Get the length of the modulus, in bits
1211  k = mpiGetBitLength(&publicKey->n);
1212 
1213  //Applications should enforce minimum and maximum key sizes
1214  if(k < SSH_MIN_RSA_MODULUS_SIZE || k > SSH_MAX_RSA_MODULUS_SIZE)
1215  return ERROR_INVALID_KEY_LENGTH;
1216 
1217  //Successful processing
1218  return NO_ERROR;
1219 #else
1220  //Not implemented
1221  return ERROR_NOT_IMPLEMENTED;
1222 #endif
1223 }
1224 
1225 
1226 /**
1227  * @brief Import a DSA host key
1228  * @param[out] publicKey Pointer to the DSA public key
1229  * @param[in] hostKey Pointer to the host key structure
1230  * @return Error code
1231  **/
1232 
1234  const SshDsaHostKey *hostKey)
1235 {
1236 #if (SSH_DSA_SIGN_SUPPORT == ENABLED)
1237  error_t error;
1238  size_t k;
1239 
1240  //Import DSA prime modulus
1241  error = mpiImport(&publicKey->params.p, hostKey->p.value, hostKey->p.length,
1243  //Any error to report?
1244  if(error)
1245  return error;
1246 
1247  //Import DSA group order
1248  error = mpiImport(&publicKey->params.q, hostKey->q.value, hostKey->q.length,
1250  //Any error to report?
1251  if(error)
1252  return error;
1253 
1254  //Import DSA group generator
1255  error = mpiImport(&publicKey->params.g, hostKey->g.value, hostKey->g.length,
1257  //Any error to report?
1258  if(error)
1259  return error;
1260 
1261  //Import DSA public key value
1262  error = mpiImport(&publicKey->y, hostKey->y.value, hostKey->y.length,
1264  //Any error to report?
1265  if(error)
1266  return error;
1267 
1268  //Get the length of the modulus, in bits
1269  k = mpiGetBitLength(&publicKey->params.p);
1270 
1271  //Applications should enforce minimum and maximum key sizes
1272  if(k < SSH_MIN_DSA_MODULUS_SIZE || k > SSH_MAX_DSA_MODULUS_SIZE)
1273  return ERROR_INVALID_KEY_LENGTH;
1274 
1275  //Successful processing
1276  return NO_ERROR;
1277 #else
1278  //Not implemented
1279  return ERROR_NOT_IMPLEMENTED;
1280 #endif
1281 }
1282 
1283 
1284 /**
1285  * @brief Import a ECDSA host key
1286  * @param[out] publicKey Pointer to the ECDSA public key
1287  * @param[in] hostKey Pointer to the host key structure
1288  * @return Error code
1289  **/
1290 
1292  const SshEcdsaHostKey *hostKey)
1293 {
1294 #if (SSH_ECDSA_SIGN_SUPPORT == ENABLED)
1295  error_t error;
1296  const EcCurve *curve;
1297 
1298  //Retrieve the elliptic curve that matches the specified key format
1299  //identifier
1300  curve = sshGetCurve(&hostKey->keyFormatId, &hostKey->curveName);
1301 
1302  //Make sure the key format identifier is acceptable
1303  if(curve != NULL)
1304  {
1305  //Import EC public key
1306  error = ecImportPublicKey(publicKey, curve, hostKey->q.value,
1307  hostKey->q.length, EC_PUBLIC_KEY_FORMAT_X963);
1308  }
1309  else
1310  {
1311  //Report an error
1312  error = ERROR_WRONG_IDENTIFIER;
1313  }
1314 
1315  //Return status code
1316  return error;
1317 #else
1318  //Not implemented
1319  return ERROR_NOT_IMPLEMENTED;
1320 #endif
1321 }
1322 
1323 
1324 /**
1325  * @brief Get SSH public key type
1326  * @param[in] input SSH public key file
1327  * @param[in] length Length of the SSH public key file
1328  * @return SSH public key type
1329  **/
1330 
1331 const char_t *sshGetPublicKeyType(const char_t *input, size_t length)
1332 {
1333  error_t error;
1334  uint_t i;
1335  size_t n;
1336  const char_t *keyType;
1337 
1338  //Initialize key type
1339  keyType = NULL;
1340 
1341  //Retrieve the length of the public key structure
1342  error = sshDecodePublicKeyFile(input, length, NULL, &n);
1343 
1344  //Check status code
1345  if(!error)
1346  {
1347  uint8_t *buffer;
1348  SshString keyFormatId;
1349 
1350  //Allocate a memory buffer to hold the public key structure
1351  buffer = sshAllocMem(n);
1352 
1353  //Successful memory allocation?
1354  if(buffer != NULL)
1355  {
1356  //Decode the content of the public key file (SSH2 or OpenSSH format)
1357  error = sshDecodePublicKeyFile(input, length, buffer, &n);
1358 
1359  //Check status
1360  if(!error)
1361  {
1362  //Decode key format identifier
1363  error = sshParseString(buffer, n, &keyFormatId);
1364  }
1365 
1366  //Check status
1367  if(!error)
1368  {
1369  //Loop through the list of supported key types
1370  for(i = 0; i < arraysize(sshKeyTypes); i++)
1371  {
1372  //Matching identifier?
1373  if(sshCompareString(&keyFormatId, sshKeyTypes[i].identifier))
1374  {
1375  keyType = sshKeyTypes[i].identifier;
1376  break;
1377  }
1378  }
1379  }
1380 
1381  //Release previously allocated memory
1382  sshFreeMem(buffer);
1383  }
1384  }
1385  else
1386  {
1387 #if (SSH_ECDSA_SIGN_SUPPORT == ENABLED)
1388  X509KeyType type;
1389  const EcCurve *curve;
1390 
1391  //Extract the type of the public key (PEM format)
1392  type = pemGetPublicKeyType(input, length);
1393 
1394  //Extract the elliptic curve parameters
1395  if(type == X509_KEY_TYPE_EC)
1396  {
1397  curve = pemGetPublicKeyCurve(input, length);
1398  }
1399  else
1400  {
1401  curve = NULL;
1402  }
1403 
1404  //Loop through the list of supported key types
1405  for(i = 0; i < arraysize(sshKeyTypes); i++)
1406  {
1407  //Matching key type?
1408  if(sshKeyTypes[i].type == type)
1409  {
1410  //EC public key?
1411  if(type == X509_KEY_TYPE_EC)
1412  {
1413  //Check curve name
1414  if(osStrcmp(sshKeyTypes[i].curveName, curve->name) == 0)
1415  {
1416  keyType = sshKeyTypes[i].identifier;
1417  break;
1418  }
1419  }
1420  else
1421  {
1422  keyType = sshKeyTypes[i].identifier;
1423  break;
1424  }
1425  }
1426  }
1427 #else
1428  X509KeyType type;
1429 
1430  //Extract the type of the public key (PEM format)
1431  type = pemGetPublicKeyType(input, length);
1432 
1433  //Loop through the list of supported key types
1434  for(i = 0; i < arraysize(sshKeyTypes); i++)
1435  {
1436  //Matching key type?
1437  if(sshKeyTypes[i].type == type)
1438  {
1439  keyType = sshKeyTypes[i].identifier;
1440  break;
1441  }
1442  }
1443 #endif
1444  }
1445 
1446  //Return key type
1447  return keyType;
1448 }
1449 
1450 
1451 /**
1452  * @brief Decode SSH public key file (SSH2 or OpenSSH format)
1453  * @param[in] input SSH public key file to decode
1454  * @param[in] inputLen Length of the SSH public key file to decode
1455  * @param[out] output Pointer to the decoded data (optional parameter)
1456  * @param[out] outputLen Length of the decoded data
1457  **/
1458 
1459 error_t sshDecodePublicKeyFile(const char_t *input, size_t inputLen,
1460  uint8_t *output, size_t *outputLen)
1461 {
1462  error_t error;
1463 
1464  //Decode SSH public key file (SSH2 format)
1465  error = sshDecodeSsh2PublicKeyFile(input, inputLen, output, outputLen);
1466 
1467  //Check status code
1468  if(error)
1469  {
1470  //Decode SSH public key file (OpenSSH format)
1471  error = sshDecodeOpenSshPublicKeyFile(input, inputLen, output, outputLen);
1472  }
1473 
1474  //Return status code
1475  return error;
1476 }
1477 
1478 
1479 /**
1480  * @brief Decode SSH public key file (SSH2 format)
1481  * @param[in] input SSH public key file to decode
1482  * @param[in] inputLen Length of the SSH public key file to decode
1483  * @param[out] output Pointer to the decoded data (optional parameter)
1484  * @param[out] outputLen Length of the decoded data
1485  **/
1486 
1487 error_t sshDecodeSsh2PublicKeyFile(const char_t *input, size_t inputLen,
1488  uint8_t *output, size_t *outputLen)
1489 {
1490  error_t error;
1491  int_t i;
1492  int_t n;
1493  bool_t separatorChar;
1494  bool_t backslashChar;
1495  bool_t continuationLine;
1496  const char_t *p;
1497 
1498  //The first line of a conforming key file must be a begin marker (refer to
1499  //RFC 4716, section 3.2)
1500  i = sshSearchMarker(input, inputLen, "---- BEGIN SSH2 PUBLIC KEY ----", 31);
1501  //Begin marker not found?
1502  if(i < 0)
1503  return ERROR_INVALID_SYNTAX;
1504 
1505  //Advance the pointer over the marker
1506  i += 31;
1507 
1508  //The last line of a conforming key file must be an end marker (refer to
1509  //RFC 4716, section 3.2)
1510  n = sshSearchMarker(input + i, inputLen - i, "---- END SSH2 PUBLIC KEY ----", 29);
1511  //End marker not found?
1512  if(n < 0)
1513  return ERROR_INVALID_SYNTAX;
1514 
1515  //Point to the key file header
1516  p = input + i;
1517  i = 0;
1518 
1519  //Initialize flags
1520  separatorChar = FALSE;
1521  backslashChar = FALSE;
1522  continuationLine = FALSE;
1523 
1524  //The key file header section consists of multiple lines
1525  while(i < n)
1526  {
1527  //End of line detected?
1528  if(p[i] == '\n' || (i + 1) == n)
1529  {
1530  //A line that is not a continuation line and that has no ':' in it
1531  //is the first line of the Base64-encoded body (refer to RFC 4716,
1532  //section 3.3)
1533  if(!continuationLine && !separatorChar)
1534  {
1535  break;
1536  }
1537 
1538  //A line is continued if the last character in the line is a '\'
1539  continuationLine = backslashChar;
1540 
1541  //Reset flags
1542  separatorChar = FALSE;
1543  backslashChar = FALSE;
1544 
1545  //Point to the next line
1546  p += i + 1;
1547  n -= i + 1;
1548  i = 0;
1549  }
1550  else
1551  {
1552  //Check current character
1553  if(p[i] == ':')
1554  {
1555  //A ':' character is used to separate header name and value
1556  separatorChar = TRUE;
1557  backslashChar = FALSE;
1558  }
1559  else if(p[i] == '\\')
1560  {
1561  //A backslash is used at the end of a continued line
1562  backslashChar = TRUE;
1563  }
1564  else if(p[i] == '\r')
1565  {
1566  //Discard current character
1567  }
1568  else
1569  {
1570  //The current line is not a continued line
1571  backslashChar = FALSE;
1572  }
1573 
1574  //Next character
1575  i++;
1576  }
1577  }
1578 
1579  //The body of the SSH public key file is Base64-encoded
1580  error = base64Decode(p, n, output, outputLen);
1581  //Failed to decode the file?
1582  if(error)
1583  return error;
1584 
1585  //Sanity check
1586  if(*outputLen == 0)
1587  return ERROR_INVALID_SYNTAX;
1588 
1589  //Successful processing
1590  return NO_ERROR;
1591 }
1592 
1593 
1594 /**
1595  * @brief Decode SSH public key file (OpenSSH format)
1596  * @param[in] input SSH public key file to decode
1597  * @param[in] inputLen Length of the SSH public key file to decode
1598  * @param[out] output Pointer to the decoded data (optional parameter)
1599  * @param[out] outputLen Length of the decoded data
1600  **/
1601 
1602 error_t sshDecodeOpenSshPublicKeyFile(const char_t *input, size_t inputLen,
1603  uint8_t *output, size_t *outputLen)
1604 {
1605  error_t error;
1606  size_t i;
1607  size_t j;
1608  size_t n;
1609  const char_t *keyType;
1610 
1611  //Initialize key type
1612  keyType = NULL;
1613 
1614  //Loop through the list of identifiers
1615  for(i = 0; i < arraysize(sshKeyTypes); i++)
1616  {
1617  //Get the length of the identifier
1618  n = osStrlen(sshKeyTypes[i].identifier);
1619 
1620  //Matching identifier?
1621  if(inputLen > n && osMemcmp(input, sshKeyTypes[i].identifier, n) == 0)
1622  {
1623  keyType = sshKeyTypes[i].identifier;
1624  break;
1625  }
1626  }
1627 
1628  //Unrecognized key type?
1629  if(keyType == NULL)
1630  return ERROR_INVALID_SYNTAX;
1631 
1632  //Get the length of the identifier string
1633  i = osStrlen(keyType);
1634 
1635  //The identifier must be followed by a whitespace character
1636  if(input[i] != ' ' && input[i] != '\t')
1637  return ERROR_INVALID_SYNTAX;
1638 
1639  //Skip whitespace characters
1640  while(i < inputLen && (input[i] == ' ' || input[i] == '\t'))
1641  {
1642  i++;
1643  }
1644 
1645  //Point to the public key
1646  j = i;
1647 
1648  //The public key may be followed by a whitespace character and a comment
1649  while(j < inputLen && (input[j] != ' ' && input[j] != '\t'))
1650  {
1651  j++;
1652  }
1653 
1654  //The public key is Base64-encoded
1655  error = base64Decode(input + i, j - i, output, outputLen);
1656  //Failed to decode the file?
1657  if(error)
1658  return error;
1659 
1660  //Sanity check
1661  if(*outputLen == 0)
1662  return ERROR_INVALID_SYNTAX;
1663 
1664  //Successful processing
1665  return NO_ERROR;
1666 }
1667 
1668 
1669 /**
1670  * @brief Decode SSH private key file (OpenSSH format)
1671  * @param[in] input SSH public key file to decode
1672  * @param[in] inputLen Length of the SSH private key file to decode
1673  * @param[out] output Pointer to the decoded data (optional parameter)
1674  * @param[out] outputLen Length of the decoded data
1675  **/
1676 
1677 error_t sshDecodeOpenSshPrivateKeyFile(const char_t *input, size_t inputLen,
1678  uint8_t *output, size_t *outputLen)
1679 {
1680  error_t error;
1681  int_t i;
1682  int_t n;
1683 
1684  //The first line of the private key file must be a begin marker
1685  i = sshSearchMarker(input, inputLen,
1686  "-----BEGIN OPENSSH PRIVATE KEY-----", 35);
1687  //Begin marker not found?
1688  if(i < 0)
1689  return ERROR_INVALID_SYNTAX;
1690 
1691  //Advance the pointer over the marker
1692  i += 35;
1693 
1694  //The last line of the private key file must be an end marker
1695  n = sshSearchMarker(input + i, inputLen - i,
1696  "-----END OPENSSH PRIVATE KEY-----", 33);
1697  //End marker not found?
1698  if(n < 0)
1699  return ERROR_INVALID_SYNTAX;
1700 
1701  //The body of the SSH private key file is Base64-encoded
1702  error = base64Decode(input + i, n, output, outputLen);
1703  //Failed to decode the file?
1704  if(error)
1705  return error;
1706 
1707  //Sanity check
1708  if(*outputLen == 0)
1709  return ERROR_INVALID_SYNTAX;
1710 
1711  //Successful processing
1712  return NO_ERROR;
1713 }
1714 
1715 
1716 /**
1717  * @brief Search a string for a given marker
1718  * @param[in] s String to search
1719  * @param[in] sLen Length of the string to search
1720  * @param[in] marker String containing the marker to search for
1721  * @param[in] markerLen Length of the marker
1722  * @return The index of the first occurrence of the marker in the string,
1723  * or -1 if the marker does not appear in the string
1724  **/
1725 
1726 int_t sshSearchMarker(const char_t *s, size_t sLen, const char_t *marker,
1727  size_t markerLen)
1728 {
1729  size_t i;
1730  size_t j;
1731 
1732  //Loop through input string
1733  for(i = 0; (i + markerLen) <= sLen; i++)
1734  {
1735  //Compare current substring with the given marker
1736  for(j = 0; j < markerLen; j++)
1737  {
1738  if(s[i + j] != marker[j])
1739  break;
1740  }
1741 
1742  //Check whether the marker has been found
1743  if(j == markerLen)
1744  return i;
1745  }
1746 
1747  //The marker does not appear in the string
1748  return -1;
1749 }
1750 
1751 #endif
error_t eddsaImportPublicKey(EddsaPublicKey *key, const EcCurve *curve, const uint8_t *data, size_t length)
Import an EdDSA public key.
Definition: eddsa.c:274
error_t sshParseOpenSshDsaPrivateKey(const uint8_t *data, size_t length, SshDsaPrivateKey *privateKey)
Parse DSA private key blob (OpenSSH format)
EdDSA private key (OpenSSH format)
error_t sshImportDsaPrivateKey(DsaPrivateKey *privateKey, const char_t *input, size_t length, const char_t *password)
Decode an SSH private key file containing a DSA private key.
SshBinaryString q
Definition: ssh_key_parse.h:67
SshBinaryString y
Definition: ssh_key_parse.h:69
@ X509_KEY_TYPE_RSA
Definition: x509_common.h:635
int bool_t
Definition: compiler_port.h:61
void rsaFreePublicKey(RsaPublicKey *key)
Release an RSA public key.
Definition: rsa.c:113
SshBinaryString q
error_t pemImportEddsaPrivateKey(EddsaPrivateKey *privateKey, const char_t *input, size_t length, const char_t *password)
Decode a PEM file containing a EdDSA private key.
Definition: pem_import.c:1228
error_t ecImportPublicKey(EcPublicKey *key, const EcCurve *curve, const uint8_t *data, size_t length, EcPublicKeyFormat format)
Import an EC public key.
Definition: ec.c:263
Mpi p
First factor.
Definition: rsa.h:72
Arbitrary precision integer.
Definition: mpi.h:102
signed int int_t
Definition: compiler_port.h:56
error_t sshParseOpenSshPrivateKeyHeader(const uint8_t *data, size_t length, SshPrivateKeyHeader *privateKeyHeader)
Parse private key header (OpenSSH format)
error_t sshParseDsaHostKey(const uint8_t *data, size_t length, SshDsaHostKey *hostKey)
Parse a DSA host key structure.
@ ERROR_NOT_IMPLEMENTED
Definition: error.h:66
DSA host key.
Definition: ssh_key_parse.h:64
SshBinaryString d
void eddsaFreePrivateKey(EddsaPrivateKey *key)
Release an EdDSA private key.
Definition: eddsa.c:95
uint8_t p
Definition: ndp.h:300
Mpi q
Group order.
Definition: dsa.h:51
uint8_t t
Definition: lldp_ext_med.h:212
void dsaFreePrivateKey(DsaPrivateKey *key)
Release a DSA private key.
Definition: dsa.c:152
ECDSA private key (OpenSSH format)
#define TRUE
Definition: os_port.h:50
error_t sshParseEd448HostKey(const uint8_t *data, size_t length, SshEddsaHostKey *hostKey)
Parse an Ed448 host key structure.
error_t pemImportRsaPrivateKey(RsaPrivateKey *privateKey, const char_t *input, size_t length, const char_t *password)
Decode a PEM file containing an RSA private key.
Definition: pem_import.c:379
uint8_t data[]
Definition: ethernet.h:222
Mpi n
Modulus.
Definition: rsa.h:69
DSA private key (OpenSSH format)
error_t sshParseString(const uint8_t *p, size_t length, SshString *string)
Parse a string.
Definition: ssh_misc.c:1148
#define ED25519_CURVE
Definition: ec_curves.h:72
const char_t * sshGetPublicKeyType(const char_t *input, size_t length)
Get SSH public key type.
SshString keyFormatId
Definition: ssh_key_parse.h:79
uint8_t type
Definition: coap_common.h:176
#define osMemcmp(p1, p2, length)
Definition: os_port.h:156
@ ERROR_OUT_OF_MEMORY
Definition: error.h:63
#define ED448_CURVE
Definition: ec_curves.h:73
SshBinaryString g
Definition: ssh_key_parse.h:68
SshBinaryString n
Definition: ssh_key_parse.h:55
@ EC_PUBLIC_KEY_FORMAT_X963
Definition: ec.h:386
#define osStrcmp(s1, s2)
Definition: os_port.h:174
SSH key parsing.
Mpi e
Public exponent.
Definition: rsa.h:59
Mpi p
Prime modulus.
Definition: dsa.h:50
#define osStrlen(s)
Definition: os_port.h:168
error_t sshParseRsaHostKey(const uint8_t *data, size_t length, SshRsaHostKey *hostKey)
Parse an RSA host key structure.
error_t pemImportDsaPublicKey(DsaPublicKey *publicKey, const char_t *input, size_t length)
Decode a PEM file containing a DSA public key.
Definition: pem_import.c:582
SSH key file import functions.
SshBinaryString q
error_t mpiSubInt(Mpi *r, const Mpi *a, mpi_sword_t b)
Subtract an integer from a multiple precision integer.
Definition: mpi.c:1018
void mpiInit(Mpi *r)
Initialize a multiple precision integer.
Definition: mpi.c:48
#define ED25519_PRIVATE_KEY_LEN
Definition: ed25519.h:40
Private key header (OpenSSH format)
bool_t sshCompareString(const SshString *string, const char_t *value)
Compare a binary string against the supplied value.
Definition: ssh_misc.c:1626
Mpi d
Private exponent.
Definition: rsa.h:71
Mpi n
Modulus.
Definition: rsa.h:58
error_t sshDecodeSsh2PublicKeyFile(const char_t *input, size_t inputLen, uint8_t *output, size_t *outputLen)
Decode SSH public key file (SSH2 format)
SshBinaryString encrypted
error_t mpiMod(Mpi *r, const Mpi *a, const Mpi *p)
Modulo operation.
Definition: mpi.c:1587
error_t sshDecryptOpenSshPrivateKey(const SshPrivateKeyHeader *privateKeyHeader, const char_t *password, const uint8_t *ciphertext, uint8_t *plaintext, size_t length)
OpenSSH private key decryption.
error_t pemImportDsaPrivateKey(DsaPrivateKey *privateKey, const char_t *input, size_t length, const char_t *password)
Decode a PEM file containing a DSA private key.
Definition: pem_import.c:662
size_t length
Definition: ssh_types.h:69
SshBinaryString q
Definition: ssh_key_parse.h:81
@ X509_KEY_TYPE_EC
Definition: x509_common.h:638
error_t base64Decode(const char_t *input, size_t inputLen, void *output, size_t *outputLen)
Base64 decoding algorithm.
Definition: base64.c:258
#define FALSE
Definition: os_port.h:46
PEM file import functions.
DSA public key.
Definition: dsa.h:61
@ ERROR_INVALID_PARAMETER
Invalid parameter.
Definition: error.h:47
error_t sshImportRsaPrivateKey(RsaPrivateKey *privateKey, const char_t *input, size_t length, const char_t *password)
Decode an SSH private key file containing an RSA private key.
error_t
Error codes.
Definition: error.h:43
Mpi g
Group generator.
Definition: dsa.h:52
SshBinaryString n
void rsaFreePrivateKey(RsaPrivateKey *key)
Release an RSA private key.
Definition: rsa.c:148
EdDSA public key.
Definition: eddsa.h:64
#define SSH_MAX_DSA_MODULUS_SIZE
Definition: ssh.h:717
Mpi q
Second factor.
Definition: rsa.h:73
const EcCurve * sshGetCurve(const SshString *keyFormatId, const SshString *curveName)
Get the elliptic curve that matches the specified key format identifier.
Definition: ssh_misc.c:1069
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
RSA private key (OpenSSH format)
const char_t * identifier
error_t mpiImport(Mpi *r, const uint8_t *input, size_t length, MpiFormat format)
Octet string to integer conversion.
Definition: mpi.c:712
SshBinaryString e
SshBinaryString p
Definition: ssh_key_parse.h:66
SshBinaryString d
error_t pemImportEcPrivateKey(EcPrivateKey *privateKey, const char_t *input, size_t length, const char_t *password)
Decode a PEM file containing an EC private key.
Definition: pem_import.c:945
@ ERROR_INVALID_KEY_LENGTH
Definition: error.h:107
error_t sshDecodePublicKeyFile(const char_t *input, size_t inputLen, uint8_t *output, size_t *outputLen)
Decode SSH public key file (SSH2 or OpenSSH format)
SshBinaryString e
Definition: ssh_key_parse.h:54
Mpi y
Public key value.
Definition: dsa.h:75
EcPublicKey q
Public key.
Definition: ec.h:436
error_t sshParseEcdsaHostKey(const uint8_t *data, size_t length, SshEcdsaHostKey *hostKey)
Parse an ECDSA host key structure.
error_t sshParseOpenSshEcdsaPrivateKey(const uint8_t *data, size_t length, SshEcdsaPrivateKey *privateKey)
Parse ECDSA private key blob (OpenSSH format)
error_t sshImportDsaHostKey(DsaPublicKey *publicKey, const SshDsaHostKey *hostKey)
Import a DSA host key.
error_t sshParseEd25519HostKey(const uint8_t *data, size_t length, SshEddsaHostKey *hostKey)
Parse an Ed25519 host key structure.
error_t sshImportEd448PrivateKey(EddsaPrivateKey *privateKey, const char_t *input, size_t length, const char_t *password)
Decode an SSH private key file containing an Ed448 private key.
Base64 encoding scheme.
EC private key.
Definition: ec.h:432
DsaDomainParameters params
DSA domain parameters.
Definition: dsa.h:62
DSA private key.
Definition: dsa.h:72
EdDSA host key.
Definition: ssh_key_parse.h:90
error_t sshDecodeOpenSshPublicKeyFile(const char_t *input, size_t inputLen, uint8_t *output, size_t *outputLen)
Decode SSH public key file (OpenSSH format)
void ecFreePrivateKey(EcPrivateKey *key)
Release an EC private key.
Definition: ec.c:100
uint8_t length
Definition: tcp.h:375
Mpi e
Public exponent.
Definition: rsa.h:70
SshBinaryString y
SshBinaryString qinv
String.
Definition: ssh_types.h:56
error_t sshImportEcdsaPrivateKey(EcPrivateKey *privateKey, const char_t *input, size_t length, const char_t *password)
Decode an SSH private key file containing an ECDSA private key.
#define SSH_MAX_RSA_MODULUS_SIZE
Definition: ssh.h:703
X509KeyType pemGetPublicKeyType(const char_t *input, size_t length)
Extract the public key type from a PEM file.
Definition: pem_import.c:1373
uint_t mpiGetBitLength(const Mpi *a)
Get the actual length in bits.
Definition: mpi.c:254
Mpi qinv
CRT coefficient.
Definition: rsa.h:76
EdDSA private key.
Definition: eddsa.h:75
Mpi dq
Second factor's CRT exponent.
Definition: rsa.h:75
const uint8_t * value
Definition: ssh_types.h:68
SshBinaryString d
error_t pemImportRsaPublicKey(RsaPublicKey *publicKey, const char_t *input, size_t length)
Decode a PEM file containing an RSA public key.
Definition: pem_import.c:252
#define ED448_PRIVATE_KEY_LEN
Definition: ed448.h:40
EC public key.
Definition: ec.h:421
char char_t
Definition: compiler_port.h:55
error_t sshDecodeOpenSshPrivateKeyFile(const char_t *input, size_t inputLen, uint8_t *output, size_t *outputLen)
Decode SSH private key file (OpenSSH format)
#define sshFreeMem(p)
Definition: ssh.h:729
error_t sshImportRsaHostKey(RsaPublicKey *publicKey, const SshRsaHostKey *hostKey)
Import an RSA host key.
SSH private key decryption.
@ X509_KEY_TYPE_ED448
Definition: x509_common.h:643
uint8_t n
RSA private key.
Definition: rsa.h:68
error_t pemImportEcPublicKey(EcPublicKey *publicKey, const char_t *input, size_t length)
Decode a PEM file containing an EC public key.
Definition: pem_import.c:865
const EcCurve * pemGetPublicKeyCurve(const char_t *input, size_t length)
Extract elliptic curve parameters from a PEM file.
Definition: pem_import.c:1455
SshBinaryString g
error_t sshParseOpenSshEd448PrivateKey(const uint8_t *data, size_t length, SshEddsaPrivateKey *privateKey)
Parse Ed448 private key blob (OpenSSH format)
@ X509_KEY_TYPE_DSA
Definition: x509_common.h:637
ECDSA host key.
Definition: ssh_key_parse.h:78
SshBinaryString q
error_t sshParseOpenSshRsaPrivateKey(const uint8_t *data, size_t length, SshRsaPrivateKey *privateKey)
Parse RSA private key blob (OpenSSH format)
error_t sshImportEcdsaPublicKey(EcPublicKey *publicKey, const char_t *input, size_t length)
Decode an SSH public key file containing an ECDSA public key.
Mpi x
Secret exponent.
Definition: dsa.h:74
SSH helper functions.
@ MPI_FORMAT_BIG_ENDIAN
Definition: mpi.h:93
Mpi y
Public key value.
Definition: dsa.h:63
@ ERROR_WRONG_IDENTIFIER
Definition: error.h:89
uint8_t identifier[]
RSA host key.
Definition: ssh_key_parse.h:52
SSH key type.
void eddsaFreePublicKey(EddsaPublicKey *key)
Release an EdDSA public key.
Definition: eddsa.c:63
@ ERROR_INVALID_SYNTAX
Definition: error.h:68
uint8_t s
Definition: igmp_common.h:234
EddsaPublicKey q
Public key.
Definition: eddsa.h:79
error_t sshImportEd25519PrivateKey(EddsaPrivateKey *privateKey, const char_t *input, size_t length, const char_t *password)
Decode an SSH private key file containing an Ed25519 private key.
error_t sshImportEcdsaHostKey(EcPublicKey *publicKey, const SshEcdsaHostKey *hostKey)
Import a ECDSA host key.
DsaDomainParameters params
DSA domain parameters.
Definition: dsa.h:73
SshBinaryString p
error_t eddsaImportPrivateKey(EddsaPrivateKey *key, const EcCurve *curve, const uint8_t *data, size_t length)
Import an EdDSA private key.
Definition: eddsa.c:371
SshBinaryString x
#define EcCurve
Definition: ec.h:346
#define sshAllocMem(size)
Definition: ssh.h:724
Mpi dp
First factor's CRT exponent.
Definition: rsa.h:74
error_t ecImportPrivateKey(EcPrivateKey *key, const EcCurve *curve, const uint8_t *data, size_t length)
Import an EC private key.
Definition: ec.c:490
SshBinaryString p
error_t sshImportRsaPublicKey(RsaPublicKey *publicKey, const char_t *input, size_t length)
Decode an SSH public key file containing an RSA public key.
unsigned int uint_t
Definition: compiler_port.h:57
SshBinaryString q
@ X509_KEY_TYPE_ED25519
Definition: x509_common.h:641
X509KeyType
Public Key types.
Definition: x509_common.h:633
Secure Shell (SSH)
SshBinaryString q
Definition: ssh_key_parse.h:92
error_t sshParseOpenSshEd25519PrivateKey(const uint8_t *data, size_t length, SshEddsaPrivateKey *privateKey)
Parse Ed25519 private key blob (OpenSSH format)
void dsaFreePublicKey(DsaPublicKey *key)
Release a DSA public key.
Definition: dsa.c:119
SshString curveName
Definition: ssh_key_parse.h:80
int_t sshSearchMarker(const char_t *s, size_t sLen, const char_t *marker, size_t markerLen)
Search a string for a given marker.
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
error_t sshImportEd448PublicKey(EddsaPublicKey *publicKey, const char_t *input, size_t length)
Decode an SSH public key file containing an Ed448 public key.
error_t pemImportEddsaPublicKey(EddsaPublicKey *publicKey, const char_t *input, size_t length)
Decode a PEM file containing a EdDSA public key.
Definition: pem_import.c:1148
void ecFreePublicKey(EcPublicKey *key)
Release an EC public key.
Definition: ec.c:68
#define arraysize(a)
Definition: os_port.h:71
void mpiFree(Mpi *r)
Release a multiple precision integer.
Definition: mpi.c:64
error_t sshImportEd25519PublicKey(EddsaPublicKey *publicKey, const char_t *input, size_t length)
Decode an SSH public key file containing an Ed25519 public key.