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