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