ssh_key_format.c
Go to the documentation of this file.
1 /**
2  * @file ssh_key_format.c
3  * @brief SSH key formatting
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_parse.h"
37 #include "ssh/ssh_key_format.h"
38 #include "ssh/ssh_misc.h"
39 #include "debug.h"
40 
41 //Check SSH stack configuration
42 #if (SSH_SUPPORT == ENABLED)
43 
44 
45 /**
46  * @brief Format an RSA public host key
47  * @param[in] publicKey Pointer to the RSA public key
48  * @param[out] p Buffer where to store the host key structure
49  * @param[out] written Length of the resulting host key structure
50  * @return Error code
51  **/
52 
54  uint8_t *p, size_t *written)
55 {
56 #if (SSH_RSA_SIGN_SUPPORT == ENABLED)
57  error_t error;
58  size_t n;
59 
60  //Total length of the public host key structure
61  *written = 0;
62 
63  //Format public key format identifier
64  error = sshFormatString("ssh-rsa", p, &n);
65  //Any error to report?
66  if(error)
67  return error;
68 
69  //Point to the next field
70  p = SSH_INC_POINTER(p, n);
71  *written += n;
72 
73  //Format RSA public exponent
74  error = sshFormatMpint(&publicKey->e, p, &n);
75  //Any error to report?
76  if(error)
77  return error;
78 
79  //Point to the next field
80  p = SSH_INC_POINTER(p, n);
81  *written += n;
82 
83  //Format RSA modulus
84  error = sshFormatMpint(&publicKey->n, p, &n);
85  //Any error to report?
86  if(error)
87  return error;
88 
89  //Total number of bytes that have been written
90  *written += n;
91 
92  //Successful processing
93  return NO_ERROR;
94 #else
95  //Not implemented
96  return ERROR_NOT_IMPLEMENTED;
97 #endif
98 }
99 
100 
101 /**
102  * @brief Format a DSA public host key
103  * @param[in] publicKey Pointer to the DSA public key
104  * @param[out] p Buffer where to store the host key structure
105  * @param[out] written Length of the resulting host key structure
106  * @return Error code
107  **/
108 
110  uint8_t *p, size_t *written)
111 {
112 #if (SSH_DSA_SIGN_SUPPORT == ENABLED)
113  error_t error;
114  size_t n;
115 
116  //Total length of the public host key structure
117  *written = 0;
118 
119  //Format public key format identifier
120  error = sshFormatString("ssh-dss", p, &n);
121  //Any error to report?
122  if(error)
123  return error;
124 
125  //Point to the next field
126  p = SSH_INC_POINTER(p, n);
127  *written += n;
128 
129  //Format DSA prime modulus
130  error = sshFormatMpint(&publicKey->params.p, p, &n);
131  //Any error to report?
132  if(error)
133  return error;
134 
135  //Point to the next field
136  p = SSH_INC_POINTER(p, n);
137  *written += n;
138 
139  //Format DSA group order
140  error = sshFormatMpint(&publicKey->params.q, p, &n);
141  //Any error to report?
142  if(error)
143  return error;
144 
145  //Point to the next field
146  p = SSH_INC_POINTER(p, n);
147  *written += n;
148 
149  //Format DSA group generator
150  error = sshFormatMpint(&publicKey->params.g, p, &n);
151  //Any error to report?
152  if(error)
153  return error;
154 
155  //Point to the next field
156  p = SSH_INC_POINTER(p, n);
157  *written += n;
158 
159  //Format DSA public key value
160  error = sshFormatMpint(&publicKey->y, p, &n);
161  //Any error to report?
162  if(error)
163  return error;
164 
165  //Total number of bytes that have been written
166  *written += n;
167 
168  //Successful processing
169  return NO_ERROR;
170 #else
171  //Not implemented
172  return ERROR_NOT_IMPLEMENTED;
173 #endif
174 }
175 
176 
177 /**
178  * @brief Format an ECDSA public host key
179  * @param[in] publicKey Pointer to the ECDSA public key
180  * @param[out] p Buffer where to store the host key structure
181  * @param[out] written Length of the resulting host key structure
182  * @return Error code
183  **/
184 
186  uint8_t *p, size_t *written)
187 {
188 #if (SSH_ECDSA_SIGN_SUPPORT == ENABLED)
189  error_t error;
190  size_t n;
191  const char_t *keyFormatId;
192  const char_t *curveName;
193 
194  //Total length of the public host key structure
195  *written = 0;
196 
197  //Invalid ECDSA public key?
198  if(publicKey->curve == NULL)
200 
201  //Check elliptic curve
202  if(osStrcmp(publicKey->curve->name, "secp256r1") == 0)
203  {
204  //Select NIST P-256 elliptic curve
205  keyFormatId = "ecdsa-sha2-nistp256";
206  curveName = "nistp256";
207  }
208  else if(osStrcmp(publicKey->curve->name, "secp384r1") == 0)
209  {
210  //Select NIST P-384 elliptic curve
211  keyFormatId = "ecdsa-sha2-nistp384";
212  curveName = "nistp384";
213  }
214  else if(osStrcmp(publicKey->curve->name, "secp521r1") == 0)
215  {
216  //Select NIST P-521 elliptic curve
217  keyFormatId = "ecdsa-sha2-nistp521";
218  curveName = "nistp521";
219  }
220  else
221  {
222  //Unknown host key algorithm
224  }
225 
226  //Format public key format identifier
227  error = sshFormatString(keyFormatId, p, &n);
228  //Any error to report?
229  if(error)
230  return error;
231 
232  //Point to the next field
233  p = SSH_INC_POINTER(p, n);
234  *written += n;
235 
236  //Format the elliptic curve domain parameter identifier
237  error = sshFormatString(curveName, p, &n);
238  //Any error to report?
239  if(error)
240  return error;
241 
242  //Point to the next field
243  p = SSH_INC_POINTER(p, n);
244  *written += n;
245 
246  //Format EC public key
247  error = ecExportPublicKey(publicKey, SSH_INC_POINTER(p, sizeof(uint32_t)),
249  //Any error to report?
250  if(error)
251  return error;
252 
253  //The octet string value is preceded by a uint32 containing its length
254  if(p != NULL)
255  {
256  STORE32BE(n, p);
257  }
258 
259  //Total number of bytes that have been written
260  *written += sizeof(uint32_t) + n;
261 
262  //Successful processing
263  return NO_ERROR;
264 #else
265  //Not implemented
266  return ERROR_NOT_IMPLEMENTED;
267 #endif
268 }
269 
270 
271 /**
272  * @brief Format an Ed25519 public host key
273  * @param[in] publicKey Pointer to the Ed25519 public key
274  * @param[out] p Buffer where to store the host key structure
275  * @param[out] written Length of the resulting host key structure
276  * @return Error code
277  **/
278 
280  uint8_t *p, size_t *written)
281 {
282 #if (SSH_ED25519_SIGN_SUPPORT == ENABLED)
283  error_t error;
284  size_t n;
285 
286  //Total length of the public host key structure
287  *written = 0;
288 
289  //Format public key format identifier
290  error = sshFormatString("ssh-ed25519", p, &n);
291  //Any error to report?
292  if(error)
293  return error;
294 
295  //Point to the next field
296  p = SSH_INC_POINTER(p, n);
297  *written += n;
298 
299  //Format Ed25519 public key
300  error = eddsaExportPublicKey(publicKey,
301  SSH_INC_POINTER(p, sizeof(uint32_t)), &n);
302  //Any error to report?
303  if(error)
304  return error;
305 
306  //The octet string value is preceded by a uint32 containing its length
307  if(p != NULL)
308  {
309  STORE32BE(n, p);
310  }
311 
312  //Total number of bytes that have been written
313  *written += sizeof(uint32_t) + n;
314 
315  //Successful processing
316  return NO_ERROR;
317 #else
318  //Not implemented
319  return ERROR_NOT_IMPLEMENTED;
320 #endif
321 }
322 
323 
324 /**
325  * @brief Format an Ed448 public host key
326  * @param[in] publicKey Pointer to the Ed448 public key
327  * @param[out] p Buffer where to store the host key structure
328  * @param[out] written Length of the resulting host key structure
329  * @return Error code
330  **/
331 
333  uint8_t *p, size_t *written)
334 {
335 #if (SSH_ED448_SIGN_SUPPORT == ENABLED)
336  error_t error;
337  size_t n;
338 
339  //Total length of the public host key structure
340  *written = 0;
341 
342  //Format public key format identifier
343  error = sshFormatString("ssh-ed448", p, &n);
344  //Any error to report?
345  if(error)
346  return error;
347 
348  //Point to the next field
349  p = SSH_INC_POINTER(p, n);
350  *written += n;
351 
352  //Format Ed448 public key
353  error = eddsaExportPublicKey(publicKey,
354  SSH_INC_POINTER(p, sizeof(uint32_t)), &n);
355  //Any error to report?
356  if(error)
357  return error;
358 
359  //The octet string value is preceded by a uint32 containing its length
360  if(p != NULL)
361  {
362  STORE32BE(n, p);
363  }
364 
365  //Total number of bytes that have been written
366  *written += sizeof(uint32_t) + n;
367 
368  //Successful processing
369  return NO_ERROR;
370 #else
371  //Not implemented
372  return ERROR_NOT_IMPLEMENTED;
373 #endif
374 }
375 
376 
377 /**
378  * @brief Format an ML-DSA public host key
379  * @param[in] publicKey Pointer to the ML-DSA public key
380  * @param[out] p Buffer where to store the host key structure
381  * @param[out] written Length of the resulting host key structure
382  * @return Error code
383  **/
384 
386  uint8_t *p, size_t *written)
387 {
388 #if (SSH_MLDSA44_SIGN_SUPPORT == ENABLED || SSH_MLDSA65_SIGN_SUPPORT == ENABLED || \
389  SSH_MLDSA87_SIGN_SUPPORT == ENABLED)
390  error_t error;
391  size_t n;
392  const char_t *keyFormatId;
393 
394  //Total length of the public host key structure
395  *written = 0;
396 
397  //Check security level
398  if(publicKey->level == MLDSA44_SECURITY_LEVEL)
399  {
400  //Select ML-DSA-44 parameter set
401  keyFormatId = "ssh-mldsa-44";
402  }
403  else if(publicKey->level == MLDSA65_SECURITY_LEVEL)
404  {
405  //Select ML-DSA-65 parameter set
406  keyFormatId = "ssh-mldsa-65";
407  }
408  else if(publicKey->level == MLDSA87_SECURITY_LEVEL)
409  {
410  //Select ML-DSA-87 parameter set
411  keyFormatId = "ssh-mldsa-87";
412  }
413  else
414  {
415  //Invalid security level
416  return ERROR_INVALID_KEY;
417  }
418 
419  //Format public key format identifier
420  error = sshFormatString(keyFormatId, p, &n);
421  //Any error to report?
422  if(error)
423  return error;
424 
425  //Point to the next field
426  p = SSH_INC_POINTER(p, n);
427  *written += n;
428 
429  //Format ML-DSA public key
430  error = mldsaExportPublicKey(publicKey,
431  SSH_INC_POINTER(p, sizeof(uint32_t)), &n);
432  //Any error to report?
433  if(error)
434  return error;
435 
436  //The octet string value is preceded by a uint32 containing its length
437  if(p != NULL)
438  {
439  STORE32BE(n, p);
440  }
441 
442  //Total number of bytes that have been written
443  *written += sizeof(uint32_t) + n;
444 
445  //Successful processing
446  return NO_ERROR;
447 #else
448  //Not implemented
449  return ERROR_NOT_IMPLEMENTED;
450 #endif
451 }
452 
453 
454 /**
455  * @brief Format private key header (OpenSSH format)
456  * @param[out] p Buffer where to store the private key header
457  * @param[out] written Length of the resulting private key header
458  * @return Error code
459  **/
460 
461 error_t sshFormatOpenSshPrivateKeyHeader(uint8_t *p, size_t *written)
462 {
463  error_t error;
464  size_t n;
465 
466  //Total length of the private key header
467  *written = 0;
468 
469  //Format magic identifier
470  if(p != NULL)
471  {
472  osMemmove(p, "openssh-key-v1", SSH_AUTH_MAGIC_SIZE);
473  }
474 
475  //Point to the next field
477  *written += SSH_AUTH_MAGIC_SIZE;
478 
479  //Format 'ciphername' field (for unencrypted keys the cipher "none" is used)
480  error = sshFormatString("none", p, &n);
481  //Any error to report?
482  if(error)
483  return error;
484 
485  //Point to the next field
486  p = SSH_INC_POINTER(p, n);
487  *written += n;
488 
489  //Format 'kdfname' field (for unencrypted keys the KDF "none" is used)
490  error = sshFormatString("none", p, &n);
491  //Any error to report?
492  if(error)
493  return error;
494 
495  //Point to the next field
496  p = SSH_INC_POINTER(p, n);
497  *written += n;
498 
499  //Format 'kdfoptions' field
500  error = sshFormatString("", p, &n);
501  //Any error to report?
502  if(error)
503  return error;
504 
505  //Point to the next field
506  p = SSH_INC_POINTER(p, n);
507  *written += n;
508 
509  //Format 'number of keys' field
510  if(p != NULL)
511  {
512  STORE32BE(1, p);
513  }
514 
515  //Total number of bytes that have been written
516  *written += sizeof(uint32_t);
517 
518  //Successful processing
519  return NO_ERROR;
520 }
521 
522 
523 /**
524  * @brief Format RSA private key blob (OpenSSH format)
525  * @param[in] privateKey Pointer to the RSA private key
526  * @param[out] p Buffer where to store the private key blob
527  * @param[out] written Length of the resulting private key blob
528  * @return Error code
529  **/
530 
532  uint8_t *p, size_t *written)
533 {
534 #if (SSH_RSA_SIGN_SUPPORT == ENABLED)
535  error_t error;
536  size_t n;
537  size_t length;
538 
539  //Total length of the private key blob
540  length = 0;
541 
542  //Format 'checkint' fields
543  if(p != NULL)
544  {
545  STORE32BE(0x12345678, p);
546  STORE32BE(0x12345678, p + sizeof(uint32_t));
547  }
548 
549  //Point to the next field
550  p = SSH_INC_POINTER(p, 2 * sizeof(uint32_t));
551  length += 2 * sizeof(uint32_t);
552 
553  //Format key format identifier
554  error = sshFormatString("ssh-rsa", p, &n);
555  //Any error to report?
556  if(error)
557  return error;
558 
559  //Point to the next field
560  p = SSH_INC_POINTER(p, n);
561  length += n;
562 
563  //Format RSA modulus
564  error = sshFormatMpint(&privateKey->n, p, &n);
565  //Any error to report?
566  if(error)
567  return error;
568 
569  //Point to the next field
570  p = SSH_INC_POINTER(p, n);
571  length += n;
572 
573  //Format RSA public exponent
574  error = sshFormatMpint(&privateKey->e, p, &n);
575  //Any error to report?
576  if(error)
577  return error;
578 
579  //Point to the next field
580  p = SSH_INC_POINTER(p, n);
581  length += n;
582 
583  //Format RSA private exponent
584  error = sshFormatMpint(&privateKey->d, p, &n);
585  //Any error to report?
586  if(error)
587  return error;
588 
589  //Point to the next field
590  p = SSH_INC_POINTER(p, n);
591  length += n;
592 
593  //Format RSA CRT coefficient
594  error = sshFormatMpint(&privateKey->qinv, p, &n);
595  //Any error to report?
596  if(error)
597  return error;
598 
599  //Point to the next field
600  p = SSH_INC_POINTER(p, n);
601  length += n;
602 
603  //Parse RSA first factor
604  error = sshFormatMpint(&privateKey->p, p, &n);
605  //Any error to report?
606  if(error)
607  return error;
608 
609  //Point to the next field
610  p = SSH_INC_POINTER(p, n);
611  length += n;
612 
613  //Parse RSA second factor
614  error = sshFormatMpint(&privateKey->q, p, &n);
615  //Any error to report?
616  if(error)
617  return error;
618 
619  //Point to the next field
620  p = SSH_INC_POINTER(p, n);
621  length += n;
622 
623  //The private key is followed by a comment
624  error = sshFormatString("", p, &n);
625  //Any error to report?
626  if(error)
627  return error;
628 
629  //Point to the next field
630  p = SSH_INC_POINTER(p, n);
631  length += n;
632 
633  //The padding size is determined by the 'ciphername' field
634  for(n = 0; (length % 8) != 0; n++, length++)
635  {
636  if(p != NULL)
637  {
638  p[n] = n + 1;
639  }
640  }
641 
642  //Total number of bytes that have been written
643  *written = length;
644 
645  //Successful processing
646  return NO_ERROR;
647 #else
648  //Not implemented
649  return ERROR_NOT_IMPLEMENTED;
650 #endif
651 }
652 
653 
654 /**
655  * @brief Format DSA private key blob (OpenSSH format)
656  * @param[in] privateKey Pointer to the DSA private key
657  * @param[out] p Buffer where to store the private key blob
658  * @param[out] written Length of the resulting private key blob
659  * @return Error code
660  **/
661 
663  uint8_t *p, size_t *written)
664 {
665 #if (SSH_DSA_SIGN_SUPPORT == ENABLED)
666  error_t error;
667  size_t n;
668  size_t length;
669 
670  //Total length of the private key blob
671  length = 0;
672 
673  //Format 'checkint' fields
674  if(p != NULL)
675  {
676  STORE32BE(0x12345678, p);
677  STORE32BE(0x12345678, p + sizeof(uint32_t));
678  }
679 
680  //Point to the next field
681  p = SSH_INC_POINTER(p, 2 * sizeof(uint32_t));
682  length += 2 * sizeof(uint32_t);
683 
684  //Format key format identifier
685  error = sshFormatString("ssh-dss", p, &n);
686  //Any error to report?
687  if(error)
688  return error;
689 
690  //Point to the next field
691  p = SSH_INC_POINTER(p, n);
692  length += n;
693 
694  //Format DSA prime modulus
695  error = sshFormatMpint(&privateKey->params.p, p, &n);
696  //Any error to report?
697  if(error)
698  return error;
699 
700  //Point to the next field
701  p = SSH_INC_POINTER(p, n);
702  length += n;
703 
704  //Format DSA group order
705  error = sshFormatMpint(&privateKey->params.q, p, &n);
706  //Any error to report?
707  if(error)
708  return error;
709 
710  //Point to the next field
711  p = SSH_INC_POINTER(p, n);
712  length += n;
713 
714  //Format DSA group generator
715  error = sshFormatMpint(&privateKey->params.g, p, &n);
716  //Any error to report?
717  if(error)
718  return error;
719 
720  //Point to the next field
721  p = SSH_INC_POINTER(p, n);
722  length += n;
723 
724  //Format DSA public key value
725  error = sshFormatMpint(&privateKey->y, p, &n);
726  //Any error to report?
727  if(error)
728  return error;
729 
730  //Point to the next field
731  p = SSH_INC_POINTER(p, n);
732  length += n;
733 
734  //Format DSA private key value
735  error = sshFormatMpint(&privateKey->x, p, &n);
736  //Any error to report?
737  if(error)
738  return error;
739 
740  //Point to the next field
741  p = SSH_INC_POINTER(p, n);
742  length += n;
743 
744  //The private key is followed by a comment
745  error = sshFormatString("", p, &n);
746  //Any error to report?
747  if(error)
748  return error;
749 
750  //Point to the next field
751  p = SSH_INC_POINTER(p, n);
752  length += n;
753 
754  //The padding size is determined by the 'ciphername' field
755  for(n = 0; (length % 8) != 0; n++, length++)
756  {
757  if(p != NULL)
758  {
759  p[n] = n + 1;
760  }
761  }
762 
763  //Total number of bytes that have been written
764  *written = length;
765 
766  //Successful processing
767  return NO_ERROR;
768 #else
769  //Not implemented
770  return ERROR_NOT_IMPLEMENTED;
771 #endif
772 }
773 
774 
775 /**
776  * @brief Format ECDSA private key blob (OpenSSH format)
777  * @param[in] privateKey Pointer to the ECDSA private key
778  * @param[out] p Buffer where to store the private key blob
779  * @param[out] written Length of the resulting private key blob
780  * @return Error code
781  **/
782 
784  uint8_t *p, size_t *written)
785 {
786 #if (SSH_ECDSA_SIGN_SUPPORT == ENABLED)
787  error_t error;
788  size_t n;
789  size_t length;
790  const char_t *keyFormatId;
791  const char_t *curveName;
792 
793  //Invalid elliptic curve?
794  if(privateKey->curve == NULL ||
795  privateKey->curve != privateKey->q.curve)
796  {
798  }
799 
800  //Total length of the private key blob
801  length = 0;
802 
803  //Format 'checkint' fields
804  if(p != NULL)
805  {
806  STORE32BE(0x12345678, p);
807  STORE32BE(0x12345678, p + sizeof(uint32_t));
808  }
809 
810  //Point to the next field
811  p = SSH_INC_POINTER(p, 2 * sizeof(uint32_t));
812  length += 2 * sizeof(uint32_t);
813 
814  //Check elliptic curve
815  if(osStrcmp(privateKey->curve->name, "secp256r1") == 0)
816  {
817  //Select NIST P-256 elliptic curve
818  keyFormatId = "ecdsa-sha2-nistp256";
819  curveName = "nistp256";
820  }
821  else if(osStrcmp(privateKey->curve->name, "secp384r1") == 0)
822  {
823  //Select NIST P-384 elliptic curve
824  keyFormatId = "ecdsa-sha2-nistp384";
825  curveName = "nistp384";
826  }
827  else if(osStrcmp(privateKey->curve->name, "secp521r1") == 0)
828  {
829  //Select NIST P-521 elliptic curve
830  keyFormatId = "ecdsa-sha2-nistp521";
831  curveName = "nistp521";
832  }
833  else
834  {
835  //Unknown host key algorithm
837  }
838 
839  //Format public key format identifier
840  error = sshFormatString(keyFormatId, p, &n);
841  //Any error to report?
842  if(error)
843  return error;
844 
845  //Point to the next field
846  p = SSH_INC_POINTER(p, n);
847  length += n;
848 
849  //Format the elliptic curve domain parameter identifier
850  error = sshFormatString(curveName, p, &n);
851  //Any error to report?
852  if(error)
853  return error;
854 
855  //Point to the next field
856  p = SSH_INC_POINTER(p, n);
857  length += n;
858 
859  //Format EC public key
860  error = ecExportPublicKey(&privateKey->q,
861  SSH_INC_POINTER(p, sizeof(uint32_t)), &n, EC_PUBLIC_KEY_FORMAT_X963);
862  //Any error to report?
863  if(error)
864  return error;
865 
866  //The octet string value is preceded by a uint32 containing its length
867  if(p != NULL)
868  {
869  STORE32BE(n, p);
870  }
871 
872  //Point to the next field
873  p = SSH_INC_POINTER(p, sizeof(uint32_t) + n);
874  length += sizeof(uint32_t) + n;
875 
876  //Get the length of the private key, in words
877  n = (privateKey->curve->orderSize + 31) / 32;
878 
879  //Format EC private key
880  error = sshConvertScalarToMpint(privateKey->d, n, p, &n);
881  //Any error to report?
882  if(error)
883  return error;
884 
885  //Point to the next field
886  p = SSH_INC_POINTER(p, n);
887  length += n;
888 
889  //The private key is followed by a comment
890  error = sshFormatString("", p, &n);
891  //Any error to report?
892  if(error)
893  return error;
894 
895  //Point to the next field
896  p = SSH_INC_POINTER(p, n);
897  length += n;
898 
899  //The padding size is determined by the 'ciphername' field
900  for(n = 0; (length % 8) != 0; n++, length++)
901  {
902  if(p != NULL)
903  {
904  p[n] = n + 1;
905  }
906  }
907 
908  //Total number of bytes that have been written
909  *written = length;
910 
911  //Successful processing
912  return NO_ERROR;
913 #else
914  //Not implemented
915  return ERROR_NOT_IMPLEMENTED;
916 #endif
917 }
918 
919 
920 /**
921  * @brief Format Ed25519 private key blob (OpenSSH format)
922  * @param[in] privateKey Pointer to the Ed25519 private key
923  * @param[out] p Buffer where to store the private key blob
924  * @param[out] written Length of the resulting private key blob
925  * @return Error code
926  **/
927 
929  uint8_t *p, size_t *written)
930 {
931 #if (SSH_ED25519_SIGN_SUPPORT == ENABLED)
932  error_t error;
933  size_t m;
934  size_t n;
935  size_t length;
936 
937  //Total length of the private key blob
938  length = 0;
939 
940  //Format 'checkint' fields
941  if(p != NULL)
942  {
943  STORE32BE(0x12345678, p);
944  STORE32BE(0x12345678, p + sizeof(uint32_t));
945  }
946 
947  //Point to the next field
948  p = SSH_INC_POINTER(p, 2 * sizeof(uint32_t));
949  length += 2 * sizeof(uint32_t);
950 
951  //Format key format identifier
952  error = sshFormatString("ssh-ed25519", p, &n);
953  //Any error to report?
954  if(error)
955  return error;
956 
957  //Point to the next field
958  p = SSH_INC_POINTER(p, n);
959  length += n;
960 
961  //Format Ed25519 public key
962  error = eddsaExportPublicKey(&privateKey->q,
963  SSH_INC_POINTER(p, sizeof(uint32_t)), &n);
964  //Any error to report?
965  if(error)
966  return error;
967 
968  //The octet string value is preceded by a uint32 containing its length
969  if(p != NULL)
970  {
971  STORE32BE(n, p);
972  }
973 
974  //Point to the next field
975  p = SSH_INC_POINTER(p, sizeof(uint32_t) + n);
976  length += sizeof(uint32_t) + n;
977 
978  //Format Ed25519 private key
979  error = eddsaExportPrivateKey(privateKey,
980  SSH_INC_POINTER(p, sizeof(uint32_t)), &m);
981  //Any error to report?
982  if(error)
983  return error;
984 
985  //Concatenate the Ed25519 public key
986  error = eddsaExportPublicKey(&privateKey->q,
987  SSH_INC_POINTER(p, sizeof(uint32_t) + m), &n);
988  //Any error to report?
989  if(error)
990  return error;
991 
992  //The octet string value is preceded by a uint32 containing its length
993  if(p != NULL)
994  {
995  STORE32BE(m + n, p);
996  }
997 
998  //Point to the next field
999  p = SSH_INC_POINTER(p, sizeof(uint32_t) + m + n);
1000  length += sizeof(uint32_t) + m + n;
1001 
1002  //The private key is followed by a comment
1003  error = sshFormatString("", p, &n);
1004  //Any error to report?
1005  if(error)
1006  return error;
1007 
1008  //Point to the next field
1009  p = SSH_INC_POINTER(p, n);
1010  length += n;
1011 
1012  //The padding size is determined by the 'ciphername' field
1013  for(n = 0; (length % 8) != 0; n++, length++)
1014  {
1015  if(p != NULL)
1016  {
1017  p[n] = n + 1;
1018  }
1019  }
1020 
1021  //Total number of bytes that have been written
1022  *written = length;
1023 
1024  //Successful processing
1025  return NO_ERROR;
1026 #else
1027  //Not implemented
1028  return ERROR_NOT_IMPLEMENTED;
1029 #endif
1030 }
1031 
1032 
1033 /**
1034  * @brief Format Ed448 private key blob (OpenSSH format)
1035  * @param[in] privateKey Pointer to the Ed448 private key
1036  * @param[out] p Buffer where to store the private key blob
1037  * @param[out] written Length of the resulting private key blob
1038  * @return Error code
1039  **/
1040 
1042  uint8_t *p, size_t *written)
1043 {
1044 #if (SSH_ED448_SIGN_SUPPORT == ENABLED)
1045  error_t error;
1046  size_t m;
1047  size_t n;
1048  size_t length;
1049 
1050  //Total length of the private key blob
1051  length = 0;
1052 
1053  //Format 'checkint' fields
1054  if(p != NULL)
1055  {
1056  STORE32BE(0x12345678, p);
1057  STORE32BE(0x12345678, p + sizeof(uint32_t));
1058  }
1059 
1060  //Point to the next field
1061  p = SSH_INC_POINTER(p, 2 * sizeof(uint32_t));
1062  length += 2 * sizeof(uint32_t);
1063 
1064  //Format key format identifier
1065  error = sshFormatString("ssh-ed448", p, &n);
1066  //Any error to report?
1067  if(error)
1068  return error;
1069 
1070  //Point to the next field
1071  p = SSH_INC_POINTER(p, n);
1072  length += n;
1073 
1074  //Format Ed448 public key
1075  error = eddsaExportPublicKey(&privateKey->q,
1076  SSH_INC_POINTER(p, sizeof(uint32_t)), &n);
1077  //Any error to report?
1078  if(error)
1079  return error;
1080 
1081  //The octet string value is preceded by a uint32 containing its length
1082  if(p != NULL)
1083  {
1084  STORE32BE(n, p);
1085  }
1086 
1087  //Point to the next field
1088  p = SSH_INC_POINTER(p, sizeof(uint32_t) + n);
1089  length += sizeof(uint32_t) + n;
1090 
1091  //Format Ed448 private key
1092  error = eddsaExportPrivateKey(privateKey,
1093  SSH_INC_POINTER(p, sizeof(uint32_t)), &m);
1094  //Any error to report?
1095  if(error)
1096  return error;
1097 
1098  //Concatenate the Ed448 public key
1099  error = eddsaExportPublicKey(&privateKey->q,
1100  SSH_INC_POINTER(p, sizeof(uint32_t) + m), &n);
1101  //Any error to report?
1102  if(error)
1103  return error;
1104 
1105  //The octet string value is preceded by a uint32 containing its length
1106  if(p != NULL)
1107  {
1108  STORE32BE(m + n, p);
1109  }
1110 
1111  //Point to the next field
1112  p = SSH_INC_POINTER(p, sizeof(uint32_t) + m + n);
1113  length += sizeof(uint32_t) + m + n;
1114 
1115  //The private key is followed by a comment
1116  error = sshFormatString("", p, &n);
1117  //Any error to report?
1118  if(error)
1119  return error;
1120 
1121  //Point to the next field
1122  p = SSH_INC_POINTER(p, n);
1123  length += n;
1124 
1125  //The padding size is determined by the 'ciphername' field
1126  for(n = 0; (length % 8) != 0; n++, length++)
1127  {
1128  if(p != NULL)
1129  {
1130  p[n] = n + 1;
1131  }
1132  }
1133 
1134  //Total number of bytes that have been written
1135  *written = length;
1136 
1137  //Successful processing
1138  return NO_ERROR;
1139 #else
1140  //Not implemented
1141  return ERROR_NOT_IMPLEMENTED;
1142 #endif
1143 }
1144 
1145 #endif
@ ERROR_UNSUPPORTED_ELLIPTIC_CURVE
Definition: error.h:133
error_t sshFormatOpenSshPrivateKeyHeader(uint8_t *p, size_t *written)
Format private key header (OpenSSH format)
error_t sshFormatOpenSshEd25519PrivateKey(const EddsaPrivateKey *privateKey, uint8_t *p, size_t *written)
Format Ed25519 private key blob (OpenSSH format)
error_t sshConvertScalarToMpint(const uint32_t *value, uint_t length, uint8_t *p, size_t *written)
Convert a scalar to mpint representation.
Definition: ssh_misc.c:1574
Mpi p
First factor.
Definition: rsa.h:72
error_t sshFormatOpenSshEcdsaPrivateKey(const EcPrivateKey *privateKey, uint8_t *p, size_t *written)
Format ECDSA private key blob (OpenSSH format)
@ ERROR_NOT_IMPLEMENTED
Definition: error.h:66
error_t sshFormatOpenSshRsaPrivateKey(const RsaPrivateKey *privateKey, uint8_t *p, size_t *written)
Format RSA private key blob (OpenSSH format)
uint8_t p
Definition: ndp.h:300
const EcCurve * curve
Elliptic curve parameters.
Definition: ec.h:433
Mpi q
Group order.
Definition: dsa.h:51
Mpi n
Modulus.
Definition: rsa.h:69
#define MLDSA87_SECURITY_LEVEL
Definition: mldsa.h:61
error_t sshFormatOpenSshEd448PrivateKey(const EddsaPrivateKey *privateKey, uint8_t *p, size_t *written)
Format Ed448 private key blob (OpenSSH format)
@ EC_PUBLIC_KEY_FORMAT_X963
Definition: ec.h:386
error_t ecExportPublicKey(const EcPublicKey *key, uint8_t *output, size_t *written, EcPublicKeyFormat format)
Export an EC public key.
Definition: ec.c:378
#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
#define MLDSA65_SECURITY_LEVEL
Definition: mldsa.h:50
error_t sshFormatEd448PublicKey(const EddsaPublicKey *publicKey, uint8_t *p, size_t *written)
Format an Ed448 public host key.
Mpi d
Private exponent.
Definition: rsa.h:71
Mpi n
Modulus.
Definition: rsa.h:58
error_t sshFormatRsaPublicKey(const RsaPublicKey *publicKey, uint8_t *p, size_t *written)
Format an RSA public host key.
error_t eddsaExportPublicKey(const EddsaPublicKey *key, uint8_t *output, size_t *written)
Export an EdDSA public key.
Definition: eddsa.c:328
#define MLDSA44_SECURITY_LEVEL
Definition: mldsa.h:39
ML-DSA public key.
Definition: mldsa.h:82
DSA public key.
Definition: dsa.h:61
error_t
Error codes.
Definition: error.h:43
Mpi g
Group generator.
Definition: dsa.h:52
EdDSA public key.
Definition: eddsa.h:64
Mpi q
Second factor.
Definition: rsa.h:73
error_t sshFormatOpenSshDsaPrivateKey(const DsaPrivateKey *privateKey, uint8_t *p, size_t *written)
Format DSA private key blob (OpenSSH format)
RSA public key.
Definition: rsa.h:57
#define SSH_INC_POINTER(p, n)
error_t mldsaExportPublicKey(const MldsaPublicKey *key, uint8_t *output, size_t *written)
Export an ML-DSA public key.
Definition: mldsa.c:225
error_t sshFormatEd25519PublicKey(const EddsaPublicKey *publicKey, uint8_t *p, size_t *written)
Format an Ed25519 public host key.
Mpi y
Public key value.
Definition: dsa.h:75
EcPublicKey q
Public key.
Definition: ec.h:436
error_t sshFormatMldsaPublicKey(const MldsaPublicKey *publicKey, uint8_t *p, size_t *written)
Format an ML-DSA public host key.
EC private key.
Definition: ec.h:432
error_t eddsaExportPrivateKey(const EddsaPrivateKey *key, uint8_t *output, size_t *written)
Export an EdDSA private key.
Definition: eddsa.c:436
DsaDomainParameters params
DSA domain parameters.
Definition: dsa.h:62
DSA private key.
Definition: dsa.h:72
SSH key formatting.
uint8_t length
Definition: tcp.h:375
Mpi e
Public exponent.
Definition: rsa.h:70
error_t sshFormatDsaPublicKey(const DsaPublicKey *publicKey, uint8_t *p, size_t *written)
Format a DSA public host key.
Mpi qinv
CRT coefficient.
Definition: rsa.h:76
EdDSA private key.
Definition: eddsa.h:75
error_t sshFormatMpint(const Mpi *value, uint8_t *p, size_t *written)
Format a multiple precision integer.
Definition: ssh_misc.c:1518
EC public key.
Definition: ec.h:421
char char_t
Definition: compiler_port.h:55
uint32_t d[EC_MAX_ORDER_SIZE]
Private key.
Definition: ec.h:434
uint8_t m
Definition: ndp.h:304
uint8_t n
RSA private key.
Definition: rsa.h:68
Mpi x
Secret exponent.
Definition: dsa.h:74
SSH helper functions.
Mpi y
Public key value.
Definition: dsa.h:63
EddsaPublicKey q
Public key.
Definition: eddsa.h:79
DsaDomainParameters params
DSA domain parameters.
Definition: dsa.h:73
error_t sshFormatString(const char_t *value, uint8_t *p, size_t *written)
Format a string.
Definition: ssh_misc.c:1410
@ ERROR_UNSUPPORTED_SIGNATURE_ALGO
Definition: error.h:132
#define SSH_AUTH_MAGIC_SIZE
Definition: ssh_key_parse.h:38
uint_t level
Security level.
Definition: mldsa.h:83
Secure Shell (SSH)
const EcCurve * curve
Elliptic curve parameters.
Definition: ec.h:422
#define STORE32BE(a, p)
Definition: cpu_endian.h:286
@ ERROR_INVALID_KEY
Definition: error.h:106
error_t sshFormatEcdsaPublicKey(const EcPublicKey *publicKey, uint8_t *p, size_t *written)
Format an ECDSA public host key.
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
#define osMemmove(dest, src, length)
Definition: os_port.h:153