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.6
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  //Initialize variable
646  data = NULL;
647 
648  //Retrieve the length of the private key structure
649  error = sshDecodeOpenSshPrivateKeyFile(input, length, NULL, &n);
650 
651  //Check status code
652  if(!error)
653  {
654  //Allocate a memory buffer to hold the private key structure
655  buffer = sshAllocMem(n);
656 
657  //Successful memory allocation?
658  if(buffer != NULL)
659  {
660  //Initialize multiple precision integer
661  mpiInit(&t);
662 
663  //Decode the content of the private key file (OpenSSH format)
664  error = sshDecodeOpenSshPrivateKeyFile(input, length, buffer, &n);
665 
666  //Check status code
667  if(!error)
668  {
669  //Parse private key header
670  error = sshParseOpenSshPrivateKeyHeader(buffer, n,
671  &privateKeyHeader);
672  }
673 
674  //Check status code
675  if(!error)
676  {
677  //Point to the encrypted data
678  data = (uint8_t *) privateKeyHeader.encrypted.value;
679  n = privateKeyHeader.encrypted.length;
680 
681  //Perform decryption operation
682  error = sshDecryptOpenSshPrivateKey(&privateKeyHeader, password,
683  data, data, n);
684  }
685 
686  //Check status code
687  if(!error)
688  {
689  //Parse RSA private key blob
690  error = sshParseOpenSshRsaPrivateKey(data, n, &privateKeyInfo);
691  }
692 
693  //Check status code
694  if(!error)
695  {
696  //Import RSA modulus
697  error = mpiImport(&privateKey->n, privateKeyInfo.n.value,
698  privateKeyInfo.n.length, MPI_FORMAT_BIG_ENDIAN);
699  }
700 
701  //Check status code
702  if(!error)
703  {
704  //Import RSA public exponent
705  error = mpiImport(&privateKey->e, privateKeyInfo.e.value,
706  privateKeyInfo.e.length, MPI_FORMAT_BIG_ENDIAN);
707  }
708 
709  //Check status code
710  if(!error)
711  {
712  //Import RSA private exponent
713  error = mpiImport(&privateKey->d, privateKeyInfo.d.value,
714  privateKeyInfo.d.length, MPI_FORMAT_BIG_ENDIAN);
715  }
716 
717  //Check status code
718  if(!error)
719  {
720  //Import RSA first factor
721  error = mpiImport(&privateKey->p, privateKeyInfo.p.value,
722  privateKeyInfo.p.length, MPI_FORMAT_BIG_ENDIAN);
723  }
724 
725  //Check status code
726  if(!error)
727  {
728  //Import RSA second factor
729  error = mpiImport(&privateKey->q, privateKeyInfo.q.value,
730  privateKeyInfo.q.length, MPI_FORMAT_BIG_ENDIAN);
731  }
732 
733  //Check status code
734  if(!error)
735  {
736  //Import RSA CRT coefficient
737  error = mpiImport(&privateKey->qinv, privateKeyInfo.qinv.value,
738  privateKeyInfo.qinv.length, MPI_FORMAT_BIG_ENDIAN);
739  }
740 
741  //Check status code
742  if(!error)
743  {
744  //Compute t = p - 1
745  error = mpiSubInt(&t, &privateKey->p, 1);
746  }
747 
748  //Check status code
749  if(!error)
750  {
751  //Compute first factor's CRT exponent
752  error = mpiMod(&privateKey->dp, &privateKey->d, &t);
753  }
754 
755  //Check status code
756  if(!error)
757  {
758  //Compute t = q - 1
759  error = mpiSubInt(&t, &privateKey->q, 1);
760  }
761 
762  //Check status code
763  if(!error)
764  {
765  //Compute second factor's CRT exponent
766  error = mpiMod(&privateKey->dq, &privateKey->d, &t);
767  }
768 
769  //Release multiple precision integers
770  mpiFree(&t);
771  //Release previously allocated memory
772  sshFreeMem(buffer);
773  }
774  else
775  {
776  //Failed to allocate memory
777  error = ERROR_OUT_OF_MEMORY;
778  }
779  }
780  else
781  {
782  //Decode the content of the private key file (PEM format)
783  error = pemImportRsaPrivateKey(privateKey, input, length, password);
784  }
785 
786  //Any error to report?
787  if(error)
788  {
789  //Clean up side effects
790  rsaFreePrivateKey(privateKey);
791  }
792 
793  //Return status code
794  return error;
795 #else
796  //Not implemented
797  return ERROR_NOT_IMPLEMENTED;
798 #endif
799 }
800 
801 
802 /**
803  * @brief Decode an SSH private key file containing a DSA private key
804  * @param[out] privateKey DSA private key resulting from the parsing process
805  * @param[in] input Pointer to the SSH private key file
806  * @param[in] length Length of the SSH private key file
807  * @param[in] password NULL-terminated string containing the password. This
808  * parameter is required if the private key is encrypted
809  * @return Error code
810  **/
811 
813  size_t length, const char_t *password)
814 {
815 #if (SSH_DSA_SIGN_SUPPORT == ENABLED)
816  error_t error;
817  size_t n;
818  uint8_t *data;
819  uint8_t *buffer;
820  SshPrivateKeyHeader privateKeyHeader;
821  SshDsaPrivateKey privateKeyInfo;
822 
823  //Check parameters
824  if(input == NULL && length != 0)
826  if(privateKey == NULL)
828 
829  //Initialize variable
830  data = NULL;
831 
832  //Retrieve the length of the private key structure
833  error = sshDecodeOpenSshPrivateKeyFile(input, length, NULL, &n);
834 
835  //Check status code
836  if(!error)
837  {
838  //Allocate a memory buffer to hold the private key structure
839  buffer = sshAllocMem(n);
840 
841  //Successful memory allocation?
842  if(buffer != NULL)
843  {
844  //Decode the content of the private key file (OpenSSH format)
845  error = sshDecodeOpenSshPrivateKeyFile(input, length, buffer, &n);
846 
847  //Check status code
848  if(!error)
849  {
850  //Parse private key header
851  error = sshParseOpenSshPrivateKeyHeader(buffer, n,
852  &privateKeyHeader);
853  }
854 
855  //Check status code
856  if(!error)
857  {
858  //Point to the encrypted data
859  data = (uint8_t *) privateKeyHeader.encrypted.value;
860  n = privateKeyHeader.encrypted.length;
861 
862  //Perform decryption operation
863  error = sshDecryptOpenSshPrivateKey(&privateKeyHeader, password,
864  data, data, n);
865  }
866 
867  //Check status code
868  if(!error)
869  {
870  //Parse DSA private key blob
871  error = sshParseOpenSshDsaPrivateKey(data, n, &privateKeyInfo);
872  }
873 
874  //Check status code
875  if(!error)
876  {
877  //Import DSA prime modulus
878  error = mpiImport(&privateKey->params.p, privateKeyInfo.p.value,
879  privateKeyInfo.p.length, MPI_FORMAT_BIG_ENDIAN);
880  }
881 
882  //Check status code
883  if(!error)
884  {
885  //Import DSA group order
886  error = mpiImport(&privateKey->params.q, privateKeyInfo.q.value,
887  privateKeyInfo.q.length, MPI_FORMAT_BIG_ENDIAN);
888  }
889 
890  //Check status code
891  if(!error)
892  {
893  //Import DSA group generator
894  error = mpiImport(&privateKey->params.g, privateKeyInfo.g.value,
895  privateKeyInfo.g.length, MPI_FORMAT_BIG_ENDIAN);
896  }
897 
898  //Check status code
899  if(!error)
900  {
901  //Import DSA private key value
902  error = mpiImport(&privateKey->x, privateKeyInfo.x.value,
903  privateKeyInfo.x.length, MPI_FORMAT_BIG_ENDIAN);
904  }
905 
906  //Check status code
907  if(!error)
908  {
909  //Import DSA public key value
910  error = mpiImport(&privateKey->y, privateKeyInfo.y.value,
911  privateKeyInfo.y.length, MPI_FORMAT_BIG_ENDIAN);
912  }
913 
914  //Release previously allocated memory
915  sshFreeMem(buffer);
916  }
917  else
918  {
919  //Failed to allocate memory
920  error = ERROR_OUT_OF_MEMORY;
921  }
922  }
923  else
924  {
925  //Decode the content of the private key file (PEM format)
926  error = pemImportDsaPrivateKey(privateKey, input, length, password);
927  }
928 
929  //Any error to report?
930  if(error)
931  {
932  //Clean up side effects
933  dsaFreePrivateKey(privateKey);
934  }
935 
936  //Return status code
937  return error;
938 #else
939  //Not implemented
940  return ERROR_NOT_IMPLEMENTED;
941 #endif
942 }
943 
944 
945 /**
946  * @brief Decode an SSH private key file containing an ECDSA private key
947  * @param[out] privateKey ECDSA private key resulting from the parsing process
948  * @param[in] input Pointer to the SSH private key file
949  * @param[in] length Length of the SSH private key file
950  * @param[in] password NULL-terminated string containing the password. This
951  * parameter is required if the private key is encrypted
952  * @return Error code
953  **/
954 
956  size_t length, const char_t *password)
957 {
958 #if (SSH_ECDSA_SIGN_SUPPORT == ENABLED)
959  error_t error;
960  size_t n;
961  uint8_t *data;
962  uint8_t *buffer;
963  SshPrivateKeyHeader privateKeyHeader;
964  SshEcdsaPrivateKey privateKeyInfo;
965  const EcCurve *curve;
966 
967  //Check parameters
968  if(input == NULL && length != 0)
970  if(privateKey == NULL)
972 
973  //Initialize variable
974  data = NULL;
975 
976  //Retrieve the length of the private key structure
977  error = sshDecodeOpenSshPrivateKeyFile(input, length, NULL, &n);
978 
979  //Check status code
980  if(!error)
981  {
982  //Allocate a memory buffer to hold the private key structure
983  buffer = sshAllocMem(n);
984 
985  //Successful memory allocation?
986  if(buffer != NULL)
987  {
988  //Decode the content of the private key file (OpenSSH format)
989  error = sshDecodeOpenSshPrivateKeyFile(input, length, buffer, &n);
990 
991  //Check status code
992  if(!error)
993  {
994  //Parse private key header
995  error = sshParseOpenSshPrivateKeyHeader(buffer, n,
996  &privateKeyHeader);
997  }
998 
999  //Check status code
1000  if(!error)
1001  {
1002  //Point to the encrypted data
1003  data = (uint8_t *) privateKeyHeader.encrypted.value;
1004  n = privateKeyHeader.encrypted.length;
1005 
1006  //Perform decryption operation
1007  error = sshDecryptOpenSshPrivateKey(&privateKeyHeader, password,
1008  data, data, n);
1009  }
1010 
1011  //Check status code
1012  if(!error)
1013  {
1014  //Parse ECDSA private key blob
1015  error = sshParseOpenSshEcdsaPrivateKey(data, n, &privateKeyInfo);
1016  }
1017 
1018  //Check status code
1019  if(!error)
1020  {
1021  //Retrieve the elliptic curve that matches the specified key format
1022  //identifier
1023  curve = sshGetCurve(&privateKeyInfo.keyFormatId,
1024  &privateKeyInfo.curveName);
1025 
1026  //Make sure the key format identifier is acceptable
1027  if(curve != NULL)
1028  {
1029  //Import EC private key
1030  error = ecImportPrivateKey(privateKey, curve,
1031  privateKeyInfo.d.value, privateKeyInfo.d.length);
1032 
1033  //Check status code
1034  if(!error)
1035  {
1036  //Import EC public key
1037  error = ecImportPublicKey(&privateKey->q, curve,
1038  privateKeyInfo.q.value, privateKeyInfo.q.length,
1040  }
1041  }
1042  else
1043  {
1044  //Report an error
1045  error = ERROR_WRONG_IDENTIFIER;
1046  }
1047  }
1048 
1049  //Release previously allocated memory
1050  sshFreeMem(buffer);
1051  }
1052  else
1053  {
1054  //Failed to allocate memory
1055  error = ERROR_OUT_OF_MEMORY;
1056  }
1057  }
1058  else
1059  {
1060  //Decode the content of the private key file (PEM format)
1061  error = pemImportEcPrivateKey(privateKey, input, length, password);
1062  }
1063 
1064  //Any error to report?
1065  if(error)
1066  {
1067  //Clean up side effects
1068  ecFreePrivateKey(privateKey);
1069  }
1070 
1071  //Return status code
1072  return error;
1073 #else
1074  //Not implemented
1075  return ERROR_NOT_IMPLEMENTED;
1076 #endif
1077 }
1078 
1079 
1080 /**
1081  * @brief Decode an SSH private key file containing an Ed25519 private key
1082  * @param[out] privateKey Ed25519 private key resulting from the parsing process
1083  * @param[in] input Pointer to the SSH private key file
1084  * @param[in] length Length of the SSH private key file
1085  * @param[in] password NULL-terminated string containing the password. This
1086  * parameter is required if the private key is encrypted
1087  * @return Error code
1088  **/
1089 
1091  const char_t *input, size_t length, const char_t *password)
1092 {
1093 #if (SSH_ED25519_SIGN_SUPPORT == ENABLED)
1094  error_t error;
1095  size_t n;
1096  uint8_t *data;
1097  uint8_t *buffer;
1098  SshPrivateKeyHeader privateKeyHeader;
1099  SshEddsaPrivateKey privateKeyInfo;
1100 
1101  //Check parameters
1102  if(input == NULL && length != 0)
1103  return ERROR_INVALID_PARAMETER;
1104  if(privateKey == NULL)
1105  return ERROR_INVALID_PARAMETER;
1106 
1107  //Initialize variable
1108  data = NULL;
1109 
1110  //Retrieve the length of the private key structure
1111  error = sshDecodeOpenSshPrivateKeyFile(input, length, NULL, &n);
1112 
1113  //Check status code
1114  if(!error)
1115  {
1116  //Allocate a memory buffer to hold the private key structure
1117  buffer = sshAllocMem(n);
1118 
1119  //Successful memory allocation?
1120  if(buffer != NULL)
1121  {
1122  //Decode the content of the private key file (OpenSSH format)
1123  error = sshDecodeOpenSshPrivateKeyFile(input, length, buffer, &n);
1124 
1125  //Check status code
1126  if(!error)
1127  {
1128  //Parse private key header
1129  error = sshParseOpenSshPrivateKeyHeader(buffer, n,
1130  &privateKeyHeader);
1131  }
1132 
1133  //Check status code
1134  if(!error)
1135  {
1136  //Point to the encrypted data
1137  data = (uint8_t *) privateKeyHeader.encrypted.value;
1138  n = privateKeyHeader.encrypted.length;
1139 
1140  //Perform decryption operation
1141  error = sshDecryptOpenSshPrivateKey(&privateKeyHeader, password,
1142  data, data, n);
1143  }
1144 
1145  //Check status code
1146  if(!error)
1147  {
1148  //Parse Ed25519 private key blob
1149  error = sshParseOpenSshEd25519PrivateKey(data, n, &privateKeyInfo);
1150  }
1151 
1152  //Check status code
1153  if(!error)
1154  {
1155  //Import Ed25519 private key
1156  error = eddsaImportPrivateKey(privateKey, ED25519_CURVE,
1157  privateKeyInfo.d.value, ED25519_PRIVATE_KEY_LEN);
1158 
1159  //Check status code
1160  if(!error)
1161  {
1162  //Import Ed25519 public key
1163  error = eddsaImportPublicKey(&privateKey->q, ED25519_CURVE,
1164  privateKeyInfo.q.value, privateKeyInfo.q.length);
1165  }
1166  }
1167 
1168  //Release previously allocated memory
1169  sshFreeMem(buffer);
1170  }
1171  else
1172  {
1173  //Failed to allocate memory
1174  error = ERROR_OUT_OF_MEMORY;
1175  }
1176  }
1177  else
1178  {
1179  //Decode the content of the private key file (PEM format)
1180  error = pemImportEddsaPrivateKey(privateKey, input, length, password);
1181  }
1182 
1183  //Any error to report?
1184  if(error)
1185  {
1186  //Clean up side effects
1187  eddsaFreePrivateKey(privateKey);
1188  }
1189 
1190  //Return status code
1191  return error;
1192 #else
1193  //Not implemented
1194  return ERROR_NOT_IMPLEMENTED;
1195 #endif
1196 }
1197 
1198 
1199 /**
1200  * @brief Decode an SSH private key file containing an Ed448 private key
1201  * @param[out] privateKey Ed448 private key resulting from the parsing process
1202  * @param[in] input Pointer to the SSH private key file
1203  * @param[in] length Length of the SSH private key file
1204  * @param[in] password NULL-terminated string containing the password. This
1205  * parameter is required if the private key is encrypted
1206  * @return Error code
1207  **/
1208 
1210  const char_t *input, size_t length, const char_t *password)
1211 {
1212 #if (SSH_ED448_SIGN_SUPPORT == ENABLED)
1213  error_t error;
1214  size_t n;
1215  uint8_t *data;
1216  uint8_t *buffer;
1217  SshPrivateKeyHeader privateKeyHeader;
1218  SshEddsaPrivateKey privateKeyInfo;
1219 
1220  //Check parameters
1221  if(input == NULL && length != 0)
1222  return ERROR_INVALID_PARAMETER;
1223  if(privateKey == NULL)
1224  return ERROR_INVALID_PARAMETER;
1225 
1226  //Initialize variable
1227  data = NULL;
1228 
1229  //Retrieve the length of the private key structure
1230  error = sshDecodeOpenSshPrivateKeyFile(input, length, NULL, &n);
1231 
1232  //Check status code
1233  if(!error)
1234  {
1235  //Allocate a memory buffer to hold the private key structure
1236  buffer = sshAllocMem(n);
1237 
1238  //Successful memory allocation?
1239  if(buffer != NULL)
1240  {
1241  //Decode the content of the private key file (OpenSSH format)
1242  error = sshDecodeOpenSshPrivateKeyFile(input, length, buffer, &n);
1243 
1244  //Check status code
1245  if(!error)
1246  {
1247  //Parse private key header
1248  error = sshParseOpenSshPrivateKeyHeader(buffer, n,
1249  &privateKeyHeader);
1250  }
1251 
1252  //Check status code
1253  if(!error)
1254  {
1255  //Point to the encrypted data
1256  data = (uint8_t *) privateKeyHeader.encrypted.value;
1257  n = privateKeyHeader.encrypted.length;
1258 
1259  //Perform decryption operation
1260  error = sshDecryptOpenSshPrivateKey(&privateKeyHeader, password,
1261  data, data, n);
1262  }
1263 
1264  //Check status code
1265  if(!error)
1266  {
1267  //Parse Ed448 private key blob
1268  error = sshParseOpenSshEd448PrivateKey(data, n, &privateKeyInfo);
1269  }
1270 
1271  //Check status code
1272  if(!error)
1273  {
1274  //Import Ed448 private key
1275  error = eddsaImportPrivateKey(privateKey, ED448_CURVE,
1276  privateKeyInfo.d.value, ED448_PRIVATE_KEY_LEN);
1277 
1278  //Check status code
1279  if(!error)
1280  {
1281  //Import Ed448 public key
1282  error = eddsaImportPublicKey(&privateKey->q, ED448_CURVE,
1283  privateKeyInfo.q.value, privateKeyInfo.q.length);
1284  }
1285  }
1286 
1287  //Release previously allocated memory
1288  sshFreeMem(buffer);
1289  }
1290  else
1291  {
1292  //Failed to allocate memory
1293  error = ERROR_OUT_OF_MEMORY;
1294  }
1295  }
1296  else
1297  {
1298  //Decode the content of the private key file (PEM format)
1299  error = pemImportEddsaPrivateKey(privateKey, input, length, password);
1300  }
1301 
1302  //Any error to report?
1303  if(error)
1304  {
1305  //Clean up side effects
1306  eddsaFreePrivateKey(privateKey);
1307  }
1308 
1309  //Return status code
1310  return error;
1311 #else
1312  //Not implemented
1313  return ERROR_NOT_IMPLEMENTED;
1314 #endif
1315 }
1316 
1317 
1318 /**
1319  * @brief Import an RSA host key
1320  * @param[out] publicKey Pointer to the RSA public key
1321  * @param[in] hostKey Pointer to the host key structure
1322  * @return Error code
1323  **/
1324 
1326  const SshRsaHostKey *hostKey)
1327 {
1328 #if (SSH_RSA_SIGN_SUPPORT == ENABLED)
1329  error_t error;
1330  uint_t k;
1331 
1332  //Import RSA public exponent
1333  error = mpiImport(&publicKey->e, hostKey->e.value, hostKey->e.length,
1335  //Any error to report?
1336  if(error)
1337  return error;
1338 
1339  //Import RSA modulus
1340  error = mpiImport(&publicKey->n, hostKey->n.value, hostKey->n.length,
1342  //Any error to report?
1343  if(error)
1344  return error;
1345 
1346  //Get the length of the modulus, in bits
1347  k = mpiGetBitLength(&publicKey->n);
1348 
1349  //Applications should enforce minimum and maximum key sizes
1350  if(k < SSH_MIN_RSA_MODULUS_SIZE || k > SSH_MAX_RSA_MODULUS_SIZE)
1351  return ERROR_INVALID_KEY_LENGTH;
1352 
1353  //Successful processing
1354  return NO_ERROR;
1355 #else
1356  //Not implemented
1357  return ERROR_NOT_IMPLEMENTED;
1358 #endif
1359 }
1360 
1361 
1362 /**
1363  * @brief Import a DSA host key
1364  * @param[out] publicKey Pointer to the DSA public key
1365  * @param[in] hostKey Pointer to the host key structure
1366  * @return Error code
1367  **/
1368 
1370  const SshDsaHostKey *hostKey)
1371 {
1372 #if (SSH_DSA_SIGN_SUPPORT == ENABLED)
1373  error_t error;
1374  size_t k;
1375 
1376  //Import DSA prime modulus
1377  error = mpiImport(&publicKey->params.p, hostKey->p.value, hostKey->p.length,
1379  //Any error to report?
1380  if(error)
1381  return error;
1382 
1383  //Import DSA group order
1384  error = mpiImport(&publicKey->params.q, hostKey->q.value, hostKey->q.length,
1386  //Any error to report?
1387  if(error)
1388  return error;
1389 
1390  //Import DSA group generator
1391  error = mpiImport(&publicKey->params.g, hostKey->g.value, hostKey->g.length,
1393  //Any error to report?
1394  if(error)
1395  return error;
1396 
1397  //Import DSA public key value
1398  error = mpiImport(&publicKey->y, hostKey->y.value, hostKey->y.length,
1400  //Any error to report?
1401  if(error)
1402  return error;
1403 
1404  //Get the length of the modulus, in bits
1405  k = mpiGetBitLength(&publicKey->params.p);
1406 
1407  //Applications should enforce minimum and maximum key sizes
1408  if(k < SSH_MIN_DSA_MODULUS_SIZE || k > SSH_MAX_DSA_MODULUS_SIZE)
1409  return ERROR_INVALID_KEY_LENGTH;
1410 
1411  //Successful processing
1412  return NO_ERROR;
1413 #else
1414  //Not implemented
1415  return ERROR_NOT_IMPLEMENTED;
1416 #endif
1417 }
1418 
1419 
1420 /**
1421  * @brief Import a ECDSA host key
1422  * @param[out] publicKey Pointer to the ECDSA public key
1423  * @param[in] hostKey Pointer to the host key structure
1424  * @return Error code
1425  **/
1426 
1428  const SshEcdsaHostKey *hostKey)
1429 {
1430 #if (SSH_ECDSA_SIGN_SUPPORT == ENABLED)
1431  error_t error;
1432  const EcCurve *curve;
1433 
1434  //Retrieve the elliptic curve that matches the specified key format
1435  //identifier
1436  curve = sshGetCurve(&hostKey->keyFormatId, &hostKey->curveName);
1437 
1438  //Make sure the key format identifier is acceptable
1439  if(curve != NULL)
1440  {
1441  //Import EC public key
1442  error = ecImportPublicKey(publicKey, curve, hostKey->q.value,
1443  hostKey->q.length, EC_PUBLIC_KEY_FORMAT_X963);
1444  }
1445  else
1446  {
1447  //Report an error
1448  error = ERROR_WRONG_IDENTIFIER;
1449  }
1450 
1451  //Return status code
1452  return error;
1453 #else
1454  //Not implemented
1455  return ERROR_NOT_IMPLEMENTED;
1456 #endif
1457 }
1458 
1459 
1460 /**
1461  * @brief Get SSH public key type
1462  * @param[in] input SSH public key file
1463  * @param[in] length Length of the SSH public key file
1464  * @return SSH public key type
1465  **/
1466 
1467 const char_t *sshGetPublicKeyType(const char_t *input, size_t length)
1468 {
1469  error_t error;
1470  uint_t i;
1471  size_t n;
1472  const char_t *keyType;
1473 
1474  //Initialize key type
1475  keyType = NULL;
1476 
1477  //Retrieve the length of the public key structure
1478  error = sshDecodePublicKeyFile(input, length, NULL, &n);
1479 
1480  //Check status code
1481  if(!error)
1482  {
1483  uint8_t *buffer;
1484  SshString keyFormatId;
1485 
1486  //Allocate a memory buffer to hold the public key structure
1487  buffer = sshAllocMem(n);
1488 
1489  //Successful memory allocation?
1490  if(buffer != NULL)
1491  {
1492  //Decode the content of the public key file (SSH2 or OpenSSH format)
1493  error = sshDecodePublicKeyFile(input, length, buffer, &n);
1494 
1495  //Check status
1496  if(!error)
1497  {
1498  //Decode key format identifier
1499  error = sshParseString(buffer, n, &keyFormatId);
1500  }
1501 
1502  //Check status
1503  if(!error)
1504  {
1505  //Loop through the list of supported key types
1506  for(i = 0; i < arraysize(sshKeyTypes); i++)
1507  {
1508  //Matching identifier?
1509  if(sshCompareString(&keyFormatId, sshKeyTypes[i].identifier))
1510  {
1511  keyType = sshKeyTypes[i].identifier;
1512  break;
1513  }
1514  }
1515  }
1516 
1517  //Release previously allocated memory
1518  sshFreeMem(buffer);
1519  }
1520  }
1521  else
1522  {
1523 #if (SSH_ECDSA_SIGN_SUPPORT == ENABLED)
1524  X509KeyType type;
1525  const EcCurve *curve;
1526 
1527  //Extract the type of the public key (PEM format)
1528  type = pemGetPublicKeyType(input, length);
1529 
1530  //Extract the elliptic curve parameters
1531  if(type == X509_KEY_TYPE_EC)
1532  {
1533  curve = pemGetPublicKeyCurve(input, length);
1534  }
1535  else
1536  {
1537  curve = NULL;
1538  }
1539 
1540  //Loop through the list of supported key types
1541  for(i = 0; i < arraysize(sshKeyTypes); i++)
1542  {
1543  //Matching key type?
1544  if(sshKeyTypes[i].type == type)
1545  {
1546  //EC public key?
1547  if(type == X509_KEY_TYPE_EC)
1548  {
1549  //Check curve name
1550  if(osStrcmp(sshKeyTypes[i].curveName, curve->name) == 0)
1551  {
1552  keyType = sshKeyTypes[i].identifier;
1553  break;
1554  }
1555  }
1556  else
1557  {
1558  keyType = sshKeyTypes[i].identifier;
1559  break;
1560  }
1561  }
1562  }
1563 #else
1564  X509KeyType type;
1565 
1566  //Extract the type of the public key (PEM format)
1567  type = pemGetPublicKeyType(input, length);
1568 
1569  //Loop through the list of supported key types
1570  for(i = 0; i < arraysize(sshKeyTypes); i++)
1571  {
1572  //Matching key type?
1573  if(sshKeyTypes[i].type == type)
1574  {
1575  keyType = sshKeyTypes[i].identifier;
1576  break;
1577  }
1578  }
1579 #endif
1580  }
1581 
1582  //Return key type
1583  return keyType;
1584 }
1585 
1586 
1587 /**
1588  * @brief Decode SSH public key file (SSH2 or OpenSSH format)
1589  * @param[in] input SSH public key file to decode
1590  * @param[in] inputLen Length of the SSH public key file to decode
1591  * @param[out] output Pointer to the decoded data (optional parameter)
1592  * @param[out] outputLen Length of the decoded data
1593  **/
1594 
1595 error_t sshDecodePublicKeyFile(const char_t *input, size_t inputLen,
1596  uint8_t *output, size_t *outputLen)
1597 {
1598  error_t error;
1599 
1600  //Decode SSH public key file (SSH2 format)
1601  error = sshDecodeSsh2PublicKeyFile(input, inputLen, output, outputLen);
1602 
1603  //Check status code
1604  if(error)
1605  {
1606  //Decode SSH public key file (OpenSSH format)
1607  error = sshDecodeOpenSshPublicKeyFile(input, inputLen, output, outputLen);
1608  }
1609 
1610  //Return status code
1611  return error;
1612 }
1613 
1614 
1615 /**
1616  * @brief Decode SSH public key file (SSH2 format)
1617  * @param[in] input SSH public key file to decode
1618  * @param[in] inputLen Length of the SSH public key file to decode
1619  * @param[out] output Pointer to the decoded data (optional parameter)
1620  * @param[out] outputLen Length of the decoded data
1621  **/
1622 
1623 error_t sshDecodeSsh2PublicKeyFile(const char_t *input, size_t inputLen,
1624  uint8_t *output, size_t *outputLen)
1625 {
1626  error_t error;
1627  int_t i;
1628  int_t n;
1629  bool_t separatorChar;
1630  bool_t backslashChar;
1631  bool_t continuationLine;
1632  const char_t *p;
1633 
1634  //The first line of a conforming key file must be a begin marker (refer to
1635  //RFC 4716, section 3.2)
1636  i = sshSearchMarker(input, inputLen, "---- BEGIN SSH2 PUBLIC KEY ----", 31);
1637  //Begin marker not found?
1638  if(i < 0)
1639  return ERROR_INVALID_SYNTAX;
1640 
1641  //Advance the pointer over the marker
1642  i += 31;
1643 
1644  //Skip CR and LF control characters
1645  while(input[i] == '\r' || input[i] == '\n')
1646  {
1647  i++;
1648  }
1649 
1650  //The last line of a conforming key file must be an end marker (refer to
1651  //RFC 4716, section 3.2)
1652  n = sshSearchMarker(input + i, inputLen - i, "---- END SSH2 PUBLIC KEY ----", 29);
1653  //End marker not found?
1654  if(n < 0)
1655  return ERROR_INVALID_SYNTAX;
1656 
1657  //Point to the key file header
1658  p = input + i;
1659  i = 0;
1660 
1661  //Initialize flags
1662  separatorChar = FALSE;
1663  backslashChar = FALSE;
1664  continuationLine = FALSE;
1665 
1666  //The key file header section consists of multiple lines
1667  while(i < n)
1668  {
1669  //End of line detected?
1670  if(p[i] == '\n' || (i + 1) == n)
1671  {
1672  //A line that is not a continuation line and that has no ':' in it
1673  //is the first line of the Base64-encoded body (refer to RFC 4716,
1674  //section 3.3)
1675  if(!continuationLine && !separatorChar)
1676  {
1677  break;
1678  }
1679 
1680  //A line is continued if the last character in the line is a '\'
1681  continuationLine = backslashChar;
1682 
1683  //Reset flags
1684  separatorChar = FALSE;
1685  backslashChar = FALSE;
1686 
1687  //Point to the next line
1688  p += i + 1;
1689  n -= i + 1;
1690  i = 0;
1691  }
1692  else
1693  {
1694  //Check current character
1695  if(p[i] == ':')
1696  {
1697  //A ':' character is used to separate header name and value
1698  separatorChar = TRUE;
1699  backslashChar = FALSE;
1700  }
1701  else if(p[i] == '\\')
1702  {
1703  //A backslash is used at the end of a continued line
1704  backslashChar = TRUE;
1705  }
1706  else if(p[i] == '\r')
1707  {
1708  //Discard current character
1709  }
1710  else
1711  {
1712  //The current line is not a continued line
1713  backslashChar = FALSE;
1714  }
1715 
1716  //Next character
1717  i++;
1718  }
1719  }
1720 
1721  //The body of the SSH public key file is Base64-encoded
1722  error = base64Decode(p, n, output, outputLen);
1723  //Failed to decode the file?
1724  if(error)
1725  return error;
1726 
1727  //Sanity check
1728  if(*outputLen == 0)
1729  return ERROR_INVALID_SYNTAX;
1730 
1731  //Successful processing
1732  return NO_ERROR;
1733 }
1734 
1735 
1736 /**
1737  * @brief Decode SSH public key file (OpenSSH format)
1738  * @param[in] input SSH public key file to decode
1739  * @param[in] inputLen Length of the SSH public key file to decode
1740  * @param[out] output Pointer to the decoded data (optional parameter)
1741  * @param[out] outputLen Length of the decoded data
1742  **/
1743 
1744 error_t sshDecodeOpenSshPublicKeyFile(const char_t *input, size_t inputLen,
1745  uint8_t *output, size_t *outputLen)
1746 {
1747  error_t error;
1748  size_t i;
1749  size_t j;
1750  size_t n;
1751  const char_t *keyType;
1752 
1753  //Initialize key type
1754  keyType = NULL;
1755 
1756  //Loop through the list of identifiers
1757  for(i = 0; i < arraysize(sshKeyTypes); i++)
1758  {
1759  //Get the length of the identifier
1760  n = osStrlen(sshKeyTypes[i].identifier);
1761 
1762  //Matching identifier?
1763  if(inputLen > n && osMemcmp(input, sshKeyTypes[i].identifier, n) == 0)
1764  {
1765  keyType = sshKeyTypes[i].identifier;
1766  break;
1767  }
1768  }
1769 
1770  //Unrecognized key type?
1771  if(keyType == NULL)
1772  return ERROR_INVALID_SYNTAX;
1773 
1774  //Get the length of the identifier string
1775  i = osStrlen(keyType);
1776 
1777  //The identifier must be followed by a whitespace character
1778  if(input[i] != ' ' && input[i] != '\t')
1779  return ERROR_INVALID_SYNTAX;
1780 
1781  //Skip whitespace characters
1782  while(i < inputLen && (input[i] == ' ' || input[i] == '\t'))
1783  {
1784  i++;
1785  }
1786 
1787  //Point to the public key
1788  j = i;
1789 
1790  //The public key may be followed by a whitespace character and a comment
1791  while(j < inputLen && (input[j] != ' ' && input[j] != '\t'))
1792  {
1793  j++;
1794  }
1795 
1796  //The public key is Base64-encoded
1797  error = base64Decode(input + i, j - i, output, outputLen);
1798  //Failed to decode the file?
1799  if(error)
1800  return error;
1801 
1802  //Sanity check
1803  if(*outputLen == 0)
1804  return ERROR_INVALID_SYNTAX;
1805 
1806  //Successful processing
1807  return NO_ERROR;
1808 }
1809 
1810 
1811 /**
1812  * @brief Decode SSH private key file (OpenSSH format)
1813  * @param[in] input SSH public key file to decode
1814  * @param[in] inputLen Length of the SSH private key file to decode
1815  * @param[out] output Pointer to the decoded data (optional parameter)
1816  * @param[out] outputLen Length of the decoded data
1817  **/
1818 
1819 error_t sshDecodeOpenSshPrivateKeyFile(const char_t *input, size_t inputLen,
1820  uint8_t *output, size_t *outputLen)
1821 {
1822  error_t error;
1823  int_t i;
1824  int_t n;
1825 
1826  //The first line of the private key file must be a begin marker
1827  i = sshSearchMarker(input, inputLen,
1828  "-----BEGIN OPENSSH PRIVATE KEY-----", 35);
1829  //Begin marker not found?
1830  if(i < 0)
1831  return ERROR_INVALID_SYNTAX;
1832 
1833  //Advance the pointer over the marker
1834  i += 35;
1835 
1836  //The last line of the private key file must be an end marker
1837  n = sshSearchMarker(input + i, inputLen - i,
1838  "-----END OPENSSH PRIVATE KEY-----", 33);
1839  //End marker not found?
1840  if(n < 0)
1841  return ERROR_INVALID_SYNTAX;
1842 
1843  //The body of the SSH private key file is Base64-encoded
1844  error = base64Decode(input + i, n, output, outputLen);
1845  //Failed to decode the file?
1846  if(error)
1847  return error;
1848 
1849  //Sanity check
1850  if(*outputLen == 0)
1851  return ERROR_INVALID_SYNTAX;
1852 
1853  //Successful processing
1854  return NO_ERROR;
1855 }
1856 
1857 
1858 /**
1859  * @brief Search a string for a given marker
1860  * @param[in] s String to search
1861  * @param[in] sLen Length of the string to search
1862  * @param[in] marker String containing the marker to search for
1863  * @param[in] markerLen Length of the marker
1864  * @return The index of the first occurrence of the marker in the string,
1865  * or -1 if the marker does not appear in the string
1866  **/
1867 
1868 int_t sshSearchMarker(const char_t *s, size_t sLen, const char_t *marker,
1869  size_t markerLen)
1870 {
1871  size_t i;
1872  size_t j;
1873 
1874  //Loop through input string
1875  for(i = 0; (i + markerLen) <= sLen; i++)
1876  {
1877  //Compare current substring with the given marker
1878  for(j = 0; j < markerLen; j++)
1879  {
1880  if(s[i + j] != marker[j])
1881  break;
1882  }
1883 
1884  //Check whether the marker has been found
1885  if(j == markerLen)
1886  return i;
1887  }
1888 
1889  //The marker does not appear in the string
1890  return -1;
1891 }
1892 
1893 #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:687
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:698
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:690
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:748
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:734
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:760
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:695
uint8_t n
RSA private key.
Definition: rsa.h:68
@ X509_KEY_TYPE_MLDSA44
Definition: x509_common.h:696
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:689
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:755
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:693
X509KeyType
Public Key types.
Definition: x509_common.h:685
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:697
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.