pem_key_export.c
Go to the documentation of this file.
1 /**
2  * @file pem_key_export.c
3  * @brief PEM key file export functions
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2026 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneCRYPTO 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 CRYPTO_TRACE_LEVEL
33 
34 //Dependencies
35 #include "core/crypto.h"
36 #include "pkix/pem_key_export.h"
37 #include "pkix/pkcs8_key_format.h"
38 #include "pkix/x509_key_format.h"
39 #include "encoding/asn1.h"
40 #include "debug.h"
41 
42 //Check crypto library configuration
43 #if (PEM_SUPPORT == ENABLED)
44 
45 
46 /**
47  * @brief Export an RSA public key to PEM format
48  * @param[in] publicKey RSA public key
49  * @param[out] output Buffer where to store the PEM string (optional parameter)
50  * @param[out] written Length of the resulting PEM string
51  * @param[in] format Desired output format (PKCS #1 or RFC 7468 format)
52  * @return Error code
53  **/
54 
56  char_t *output, size_t *written, PemPublicKeyFormat format)
57 {
58 #if (RSA_SUPPORT == ENABLED)
59  error_t error;
60  size_t length;
61 
62  //Check parameters
63  if(publicKey == NULL || written == NULL)
65 
66  //Check output format
67  if(format == PEM_PUBLIC_KEY_FORMAT_PKCS1)
68  {
69  //Format RSAPublicKey structure
70  error = x509ExportRsaPublicKey(publicKey, (uint8_t *) output, &length);
71 
72  //Check status code
73  if(!error)
74  {
75  //PKCS #1 public keys are encoded using the "RSA PUBLIC KEY" label
76  error = pemEncodeFile(output, length, "RSA PUBLIC KEY", output,
77  written);
78  }
79  }
80  else if(format == PEM_PUBLIC_KEY_FORMAT_RFC7468 ||
82  {
83  X509SubjectPublicKeyInfo publicKeyInfo;
84 
85  //Clear the SubjectPublicKeyInfo structure
86  osMemset(&publicKeyInfo, 0, sizeof(X509SubjectPublicKeyInfo));
87 
88  //The ASN.1 encoded data of the public key is the SubjectPublicKeyInfo
89  //structure (refer to RFC 7468, section 13)
90  publicKeyInfo.oid.value = RSA_ENCRYPTION_OID;
91  publicKeyInfo.oid.length = sizeof(RSA_ENCRYPTION_OID);
92 
93  //Format the SubjectPublicKeyInfo structure
94  error = x509FormatSubjectPublicKeyInfo(&publicKeyInfo, publicKey, NULL,
95  (uint8_t *) output, &length);
96 
97  //Check status code
98  if(!error)
99  {
100  //Public keys are encoded using the "PUBLIC KEY" label (see RFC 7468,
101  //section 13)
102  error = pemEncodeFile(output, length, "PUBLIC KEY", output, written);
103  }
104  }
105  else
106  {
107  //Invalid format
108  error = ERROR_INVALID_PARAMETER;
109  }
110 
111  //Return status code
112  return error;
113 #else
114  //Not implemented
115  return ERROR_NOT_IMPLEMENTED;
116 #endif
117 }
118 
119 
120 /**
121  * @brief Export an RSA private key to PEM format
122  * @param[in] privateKey RSA private key
123  * @param[out] output Buffer where to store the PEM string (optional parameter)
124  * @param[out] written Length of the resulting PEM string
125  * @param[in] format Desired output format (PKCS #1 or PKCS #8 format)
126  * @return Error code
127  **/
128 
130  char_t *output, size_t *written, PemPrivateKeyFormat format)
131 {
132 #if (RSA_SUPPORT == ENABLED)
133  error_t error;
134  size_t length;
135 
136  //Check parameters
137  if(privateKey == NULL || written == NULL)
139 
140  //Check output format
141  if(format == PEM_PRIVATE_KEY_FORMAT_PKCS1)
142  {
143  //Format RSAPrivateKey structure
144  error = x509ExportRsaPrivateKey(privateKey, (uint8_t *) output, &length);
145 
146  //Check status code
147  if(!error)
148  {
149  //PKCS #1 private keys are encoded using the "RSA PRIVATE KEY" label
150  error = pemEncodeFile(output, length, "RSA PRIVATE KEY", output,
151  written);
152  }
153  }
154  else if(format == PEM_PRIVATE_KEY_FORMAT_PKCS8 ||
156  {
157  size_t n;
158  uint8_t *p;
159  Asn1Tag tag;
160 
161  //Point to the buffer where to write the PrivateKeyInfo structure
162  p = (uint8_t *) output;
163  //Total length of the PrivateKeyInfo structure
164  length = 0;
165 
166  //Format Version field (refer to RFC 5208, section 5)
167  error = asn1WriteInt32(PKCS8_VERSION_1, FALSE, p, &n);
168 
169  //Check status code
170  if(!error)
171  {
172  X509SubjectPublicKeyInfo publicKeyInfo;
173 
174  //Advance data pointer
175  ASN1_INC_POINTER(p, n);
176  length += n;
177 
178  //Clear the SubjectPublicKeyInfo structure
179  osMemset(&publicKeyInfo, 0, sizeof(X509SubjectPublicKeyInfo));
180 
181  //The PrivateKeyAlgorithm identifies the private-key algorithm
182  publicKeyInfo.oid.value = RSA_ENCRYPTION_OID;
183  publicKeyInfo.oid.length = sizeof(RSA_ENCRYPTION_OID);
184 
185  //Format PrivateKeyAlgorithm field
186  error = x509FormatAlgoId(&publicKeyInfo, NULL, p, &n);
187  }
188 
189  //Check status code
190  if(!error)
191  {
192  //Advance data pointer
193  ASN1_INC_POINTER(p, n);
194  length += n;
195 
196  //Format PrivateKey field
197  error = pkcs8FormatRsaPrivateKey(privateKey, p, &n);
198  }
199 
200  //Check status code
201  if(!error)
202  {
203  //Update the length of the PrivateKeyInfo structure
204  length += n;
205 
206  //The PrivateKeyInfo structure is encapsulated within a sequence
207  tag.constructed = TRUE;
210  tag.length = length;
211 
212  //Write the corresponding ASN.1 tag
213  error = asn1InsertHeader(&tag, (uint8_t *) output, &n);
214  }
215 
216  //Check status code
217  if(!error)
218  {
219  //Get the length of the PrivateKeyInfo structure
220  length = tag.totalLength;
221 
222  //Unencrypted PKCS #8 private keys are encoded using the "PRIVATE KEY"
223  //label (refer to RFC 7468, section 10)
224  error = pemEncodeFile(output, length, "PRIVATE KEY", output, written);
225  }
226  }
227  else
228  {
229  //Invalid format
230  error = ERROR_INVALID_PARAMETER;
231  }
232 
233  //Return status code
234  return error;
235 #else
236  //Not implemented
237  return ERROR_NOT_IMPLEMENTED;
238 #endif
239 }
240 
241 
242 /**
243  * @brief Export an RSA-PSS public key to PEM format
244  * @param[in] publicKey RSA-PSS public key
245  * @param[out] output Buffer where to store the PEM string (optional parameter)
246  * @param[out] written Length of the resulting PEM string
247  * @param[in] format Desired output format (RFC 7468 format only)
248  * @return Error code
249  **/
250 
252  char_t *output, size_t *written, PemPublicKeyFormat format)
253 {
254 #if (RSA_SUPPORT == ENABLED)
255  error_t error;
256  size_t length;
257 
258  //Check parameters
259  if(publicKey == NULL || written == NULL)
261 
262  //Check output format
263  if(format == PEM_PUBLIC_KEY_FORMAT_RFC7468 ||
265  {
266  X509SubjectPublicKeyInfo publicKeyInfo;
267 
268  //Clear the SubjectPublicKeyInfo structure
269  osMemset(&publicKeyInfo, 0, sizeof(X509SubjectPublicKeyInfo));
270 
271  //The ASN.1 encoded data of the public key is the SubjectPublicKeyInfo
272  //structure (refer to RFC 7468, section 13)
273  publicKeyInfo.oid.value = RSASSA_PSS_OID;
274  publicKeyInfo.oid.length = sizeof(RSASSA_PSS_OID);
275 
276  //Format the SubjectPublicKeyInfo structure
277  error = x509FormatSubjectPublicKeyInfo(&publicKeyInfo, publicKey, NULL,
278  (uint8_t *) output, &length);
279 
280  //Check status code
281  if(!error)
282  {
283  //Public keys are encoded using the "PUBLIC KEY" label (see RFC 7468,
284  //section 13)
285  error = pemEncodeFile(output, length, "PUBLIC KEY", output, written);
286  }
287  }
288  else
289  {
290  //Invalid format
291  error = ERROR_INVALID_PARAMETER;
292  }
293 
294  //Return status code
295  return error;
296 #else
297  //Not implemented
298  return ERROR_NOT_IMPLEMENTED;
299 #endif
300 }
301 
302 
303 /**
304  * @brief Export an RSA-PSS private key to PEM format
305  * @param[in] privateKey RSA-PSS private key
306  * @param[out] output Buffer where to store the PEM string (optional parameter)
307  * @param[out] written Length of the resulting PEM string
308  * @param[in] format Desired output format (PKCS #8 format only)
309  * @return Error code
310  **/
311 
313  char_t *output, size_t *written, PemPrivateKeyFormat format)
314 {
315 #if (RSA_SUPPORT == ENABLED)
316  error_t error;
317  size_t length;
318 
319  //Check parameters
320  if(privateKey == NULL || written == NULL)
322 
323  //Check output format
324  if(format == PEM_PRIVATE_KEY_FORMAT_PKCS8 ||
326  {
327  size_t n;
328  uint8_t *p;
329  Asn1Tag tag;
330 
331  //Point to the buffer where to write the PrivateKeyInfo structure
332  p = (uint8_t *) output;
333  //Total length of the PrivateKeyInfo structure
334  length = 0;
335 
336  //Format Version field (refer to RFC 5208, section 5)
337  error = asn1WriteInt32(PKCS8_VERSION_1, FALSE, p, &n);
338 
339  //Check status code
340  if(!error)
341  {
342  X509SubjectPublicKeyInfo publicKeyInfo;
343 
344  //Advance data pointer
345  ASN1_INC_POINTER(p, n);
346  length += n;
347 
348  //Clear the SubjectPublicKeyInfo structure
349  osMemset(&publicKeyInfo, 0, sizeof(X509SubjectPublicKeyInfo));
350 
351  //The PrivateKeyAlgorithm identifies the private-key algorithm
352  publicKeyInfo.oid.value = RSASSA_PSS_OID;
353  publicKeyInfo.oid.length = sizeof(RSASSA_PSS_OID);
354 
355  //Format PrivateKeyAlgorithm field
356  error = x509FormatAlgoId(&publicKeyInfo, NULL, p, &n);
357  }
358 
359  //Check status code
360  if(!error)
361  {
362  //Advance data pointer
363  ASN1_INC_POINTER(p, n);
364  length += n;
365 
366  //Format PrivateKey field
367  error = pkcs8FormatRsaPrivateKey(privateKey, p, &n);
368  }
369 
370  //Check status code
371  if(!error)
372  {
373  //Update the length of the PrivateKeyInfo structure
374  length += n;
375 
376  //The PrivateKeyInfo structure is encapsulated within a sequence
377  tag.constructed = TRUE;
380  tag.length = length;
381 
382  //Write the corresponding ASN.1 tag
383  error = asn1InsertHeader(&tag, (uint8_t *) output, &n);
384  }
385 
386  //Check status code
387  if(!error)
388  {
389  //Get the length of the PrivateKeyInfo structure
390  length = tag.totalLength;
391 
392  //Unencrypted PKCS #8 private keys are encoded using the "PRIVATE KEY"
393  //label (refer to RFC 7468, section 10)
394  error = pemEncodeFile(output, length, "PRIVATE KEY", output, written);
395  }
396  }
397  else
398  {
399  //Invalid format
400  error = ERROR_INVALID_PARAMETER;
401  }
402 
403  //Return status code
404  return error;
405 #else
406  //Not implemented
407  return ERROR_NOT_IMPLEMENTED;
408 #endif
409 }
410 
411 
412 /**
413  * @brief Export a DSA public key to PEM format
414  * @param[in] publicKey DSA public key
415  * @param[out] output Buffer where to store the PEM string (optional parameter)
416  * @param[out] written Length of the resulting PEM string
417  * @param[in] format Desired output format (RFC 7468 format only)
418  * @return Error code
419  **/
420 
422  char_t *output, size_t *written, PemPublicKeyFormat format)
423 {
424 #if (DSA_SUPPORT == ENABLED)
425  error_t error;
426  size_t length;
427 
428  //Check parameters
429  if(publicKey == NULL || written == NULL)
431 
432  //Check output format
433  if(format == PEM_PUBLIC_KEY_FORMAT_RFC7468 ||
435  {
436  X509SubjectPublicKeyInfo publicKeyInfo;
437 
438  //Clear the SubjectPublicKeyInfo structure
439  osMemset(&publicKeyInfo, 0, sizeof(X509SubjectPublicKeyInfo));
440 
441  //The ASN.1 encoded data of the public key is the SubjectPublicKeyInfo
442  //structure (refer to RFC 7468, section 13)
443  publicKeyInfo.oid.value = DSA_OID;
444  publicKeyInfo.oid.length = sizeof(DSA_OID);
445 
446  //Format the SubjectPublicKeyInfo structure
447  error = x509FormatSubjectPublicKeyInfo(&publicKeyInfo, publicKey, NULL,
448  (uint8_t *) output, &length);
449 
450  //Check status code
451  if(!error)
452  {
453  //Public keys are encoded using the "PUBLIC KEY" label (see RFC 7468,
454  //section 13)
455  error = pemEncodeFile(output, length, "PUBLIC KEY", output, written);
456  }
457  }
458  else
459  {
460  //Invalid format
461  error = ERROR_INVALID_PARAMETER;
462  }
463 
464  //Return status code
465  return error;
466 #else
467  //Not implemented
468  return ERROR_NOT_IMPLEMENTED;
469 #endif
470 }
471 
472 
473 /**
474  * @brief Export a DSA private key to PEM format
475  * @param[in] privateKey DSA private key
476  * @param[out] output Buffer where to store the PEM string (optional parameter)
477  * @param[out] written Length of the resulting PEM string
478  * @param[in] format Desired output format (PKCS #8 format only)
479  * @return Error code
480  **/
481 
483  char_t *output, size_t *written, PemPrivateKeyFormat format)
484 {
485 #if (DSA_SUPPORT == ENABLED)
486  error_t error;
487  size_t length;
488 
489  //Check parameters
490  if(privateKey == NULL || written == NULL)
492 
493  //Check output format
494  if(format == PEM_PRIVATE_KEY_FORMAT_PKCS8 ||
496  {
497  size_t n;
498  uint8_t *p;
499  Asn1Tag tag;
500 
501  //Point to the buffer where to write the PrivateKeyInfo structure
502  p = (uint8_t *) output;
503  //Total length of the PrivateKeyInfo structure
504  length = 0;
505 
506  //Format Version field (refer to RFC 5208, section 5)
507  error = asn1WriteInt32(PKCS8_VERSION_1, FALSE, p, &n);
508 
509  //Check status code
510  if(!error)
511  {
512  X509SubjectPublicKeyInfo publicKeyInfo;
513 
514  //Advance data pointer
515  ASN1_INC_POINTER(p, n);
516  length += n;
517 
518  //Clear the SubjectPublicKeyInfo structure
519  osMemset(&publicKeyInfo, 0, sizeof(X509SubjectPublicKeyInfo));
520 
521  //The PrivateKeyAlgorithm identifies the private-key algorithm
522  publicKeyInfo.oid.value = DSA_OID;
523  publicKeyInfo.oid.length = sizeof(DSA_OID);
524 
525  //Format PrivateKeyAlgorithm field
526  error = x509FormatAlgoId(&publicKeyInfo, &privateKey->params,
527  p, &n);
528  }
529 
530  //Check status code
531  if(!error)
532  {
533  //Advance data pointer
534  ASN1_INC_POINTER(p, n);
535  length += n;
536 
537  //Format PrivateKey field
538  error = pkcs8FormatDsaPrivateKey(privateKey, p, &n);
539  }
540 
541  //Check status code
542  if(!error)
543  {
544  //Update the length of the PrivateKeyInfo structure
545  length += n;
546 
547  //The PrivateKeyInfo structure is encapsulated within a sequence
548  tag.constructed = TRUE;
551  tag.length = length;
552 
553  //Write the corresponding ASN.1 tag
554  error = asn1InsertHeader(&tag, (uint8_t *) output, &n);
555  }
556 
557  //Check status code
558  if(!error)
559  {
560  //Get the length of the PrivateKeyInfo structure
561  length = tag.totalLength;
562 
563  //Unencrypted PKCS #8 private keys are encoded using the "PRIVATE KEY"
564  //label (refer to RFC 7468, section 10)
565  error = pemEncodeFile(output, length, "PRIVATE KEY", output, written);
566  }
567  }
568  else
569  {
570  //Invalid format
571  error = ERROR_INVALID_PARAMETER;
572  }
573 
574  //Return status code
575  return error;
576 #else
577  //Not implemented
578  return ERROR_NOT_IMPLEMENTED;
579 #endif
580 }
581 
582 
583 /**
584  * @brief Export an EC public key to PEM format
585  * @param[in] publicKey EC public key
586  * @param[out] output Buffer where to store the PEM string (optional parameter)
587  * @param[out] written Length of the resulting PEM string
588  * @param[in] format Desired output format (RFC 7468 format only)
589  * @return Error code
590  **/
591 
593  char_t *output, size_t *written, PemPublicKeyFormat format)
594 {
595 #if (EC_SUPPORT == ENABLED)
596  error_t error;
597  size_t length;
598 
599  //Check parameters
600  if(publicKey == NULL || written == NULL)
602 
603  //Invalid elliptic curve?
604  if(publicKey->curve == NULL)
606 
607  //Check output format
608  if(format == PEM_PUBLIC_KEY_FORMAT_RFC7468 ||
610  {
611  X509SubjectPublicKeyInfo publicKeyInfo;
612 
613  //Clear the SubjectPublicKeyInfo structure
614  osMemset(&publicKeyInfo, 0, sizeof(X509SubjectPublicKeyInfo));
615 
616  //The ASN.1 encoded data of the public key is the SubjectPublicKeyInfo
617  //structure (refer to RFC 7468, section 13)
618  publicKeyInfo.oid.value = EC_PUBLIC_KEY_OID;
619  publicKeyInfo.oid.length = sizeof(EC_PUBLIC_KEY_OID);
620  publicKeyInfo.ecParams.namedCurve.value = publicKey->curve->oid;
621  publicKeyInfo.ecParams.namedCurve.length = publicKey->curve->oidSize;
622 
623  //Format the SubjectPublicKeyInfo structure
624  error = x509FormatSubjectPublicKeyInfo(&publicKeyInfo, publicKey, NULL,
625  (uint8_t *) output, &length);
626 
627  //Check status code
628  if(!error)
629  {
630  //Public keys are encoded using the "PUBLIC KEY" label (see RFC 7468,
631  //section 13)
632  error = pemEncodeFile(output, length, "PUBLIC KEY", output, written);
633  }
634  }
635  else
636  {
637  //Invalid format
638  error = ERROR_INVALID_PARAMETER;
639  }
640 
641  //Return status code
642  return error;
643 #else
644  //Not implemented
645  return ERROR_NOT_IMPLEMENTED;
646 #endif
647 }
648 
649 
650 /**
651  * @brief Export an EC private key to PEM format
652  * @param[in] privateKey EC private key
653  * @param[out] output Buffer where to store the PEM string (optional parameter)
654  * @param[out] written Length of the resulting PEM string
655  * @param[in] format Desired output format (RFC 5915 or PKCS #8 format)
656  * @return Error code
657  **/
658 
660  char_t *output, size_t *written, PemPrivateKeyFormat format)
661 {
662 #if (EC_SUPPORT == ENABLED)
663  error_t error;
664  size_t length;
665 
666  //Check parameters
667  if(privateKey == NULL || written == NULL)
669 
670  //Invalid elliptic curve?
671  if(privateKey->curve == NULL)
673 
674  //Check output format
675  if(format == PEM_PRIVATE_KEY_FORMAT_RFC5915)
676  {
677  //Format ECPrivateKey structure
678  error = x509ExportEcPrivateKey(privateKey->curve, privateKey,
679  &privateKey->q, (uint8_t *) output, &length);
680 
681  //Check status code
682  if(!error)
683  {
684  //The Base64 encoding of the DER-encoded ECPrivateKey object is
685  //sandwiched between "-----BEGIN EC PRIVATE KEY-----" and
686  //"-----END EC PRIVATE KEY-----" (refer to RFC 5915, section 4)
687  error = pemEncodeFile(output, length, "EC PRIVATE KEY", output,
688  written);
689  }
690  }
691  else if(format == PEM_PRIVATE_KEY_FORMAT_PKCS8 ||
693  {
694  size_t n;
695  uint8_t *p;
696  Asn1Tag tag;
697 
698  //Point to the buffer where to write the PrivateKeyInfo structure
699  p = (uint8_t *) output;
700  //Total length of the PrivateKeyInfo structure
701  length = 0;
702 
703  //Format Version field (refer to RFC 5208, section 5)
704  error = asn1WriteInt32(PKCS8_VERSION_1, FALSE, p, &n);
705 
706  //Check status code
707  if(!error)
708  {
709  X509SubjectPublicKeyInfo publicKeyInfo;
710 
711  //Advance data pointer
712  ASN1_INC_POINTER(p, n);
713  length += n;
714 
715  //Clear the SubjectPublicKeyInfo structure
716  osMemset(&publicKeyInfo, 0, sizeof(X509SubjectPublicKeyInfo));
717 
718  //The PrivateKeyAlgorithm identifies the private-key algorithm
719  publicKeyInfo.oid.value = EC_PUBLIC_KEY_OID;
720  publicKeyInfo.oid.length = sizeof(EC_PUBLIC_KEY_OID);
721  publicKeyInfo.ecParams.namedCurve.value = privateKey->curve->oid;
722  publicKeyInfo.ecParams.namedCurve.length = privateKey->curve->oidSize;
723 
724  //Format PrivateKeyAlgorithm field
725  error = x509FormatAlgoId(&publicKeyInfo, NULL, p, &n);
726  }
727 
728  //Check status code
729  if(!error)
730  {
731  //Advance data pointer
732  ASN1_INC_POINTER(p, n);
733  length += n;
734 
735  //Format PrivateKey field
736  error = pkcs8FormatEcPrivateKey(privateKey, p, &n);
737  }
738 
739  //Check status code
740  if(!error)
741  {
742  //Update the length of the PrivateKeyInfo structure
743  length += n;
744 
745  //The PrivateKeyInfo structure is encapsulated within a sequence
746  tag.constructed = TRUE;
749  tag.length = length;
750 
751  //Write the corresponding ASN.1 tag
752  error = asn1InsertHeader(&tag, (uint8_t *) output, &n);
753  }
754 
755  //Check status code
756  if(!error)
757  {
758  //Get the length of the PrivateKeyInfo structure
759  length = tag.totalLength;
760 
761  //Unencrypted PKCS #8 private keys are encoded using the "PRIVATE KEY"
762  //label (refer to RFC 7468, section 10)
763  error = pemEncodeFile(output, length, "PRIVATE KEY", output, written);
764  }
765  }
766  else
767  {
768  //Invalid format
769  error = ERROR_INVALID_PARAMETER;
770  }
771 
772  //Return status code
773  return error;
774 #else
775  //Not implemented
776  return ERROR_NOT_IMPLEMENTED;
777 #endif
778 }
779 
780 
781 /**
782  * @brief Export an EdDSA public key to PEM format
783  * @param[in] publicKey EdDSA public key
784  * @param[out] output Buffer where to store the PEM string (optional parameter)
785  * @param[out] written Length of the resulting PEM string
786  * @param[in] format Desired output format (RFC 7468 format only)
787  * @return Error code
788  **/
789 
791  char_t *output, size_t *written, PemPublicKeyFormat format)
792 {
793 #if (ED25519_SUPPORT == ENABLED || ED448_SUPPORT == ENABLED)
794  error_t error;
795  size_t length;
796 
797  //Check parameters
798  if(publicKey == NULL || written == NULL)
800 
801  //Invalid elliptic curve?
802  if(publicKey->curve == NULL)
804 
805  //Check output format
806  if(format == PEM_PUBLIC_KEY_FORMAT_RFC7468 ||
808  {
809  X509SubjectPublicKeyInfo publicKeyInfo;
810 
811  //Clear the SubjectPublicKeyInfo structure
812  osMemset(&publicKeyInfo, 0, sizeof(X509SubjectPublicKeyInfo));
813 
814  //The ASN.1 encoded data of the public key is the SubjectPublicKeyInfo
815  //structure (refer to RFC 7468, section 13)
816  publicKeyInfo.oid.value = publicKey->curve->oid;
817  publicKeyInfo.oid.length = publicKey->curve->oidSize;
818 
819  //Format the SubjectPublicKeyInfo structure
820  error = x509FormatSubjectPublicKeyInfo(&publicKeyInfo, publicKey, NULL,
821  (uint8_t *) output, &length);
822 
823  //Check status code
824  if(!error)
825  {
826  //Public keys are encoded using the "PUBLIC KEY" label (see RFC 7468,
827  //section 13)
828  error = pemEncodeFile(output, length, "PUBLIC KEY", output, written);
829  }
830  }
831  else
832  {
833  //Invalid format
834  error = ERROR_INVALID_PARAMETER;
835  }
836 
837  //Return status code
838  return error;
839 #else
840  //Not implemented
841  return ERROR_NOT_IMPLEMENTED;
842 #endif
843 }
844 
845 
846 /**
847  * @brief Export an EdDSA private key to PEM format
848  * @param[in] privateKey EdDSA private key
849  * @param[out] output Buffer where to store the PEM string (optional parameter)
850  * @param[out] written Length of the resulting PEM string
851  * @param[in] format Desired output format (PKCS #8 v1 or v2 format)
852  * @return Error code
853  **/
854 
856  char_t *output, size_t *written, PemPrivateKeyFormat format)
857 {
858 #if (ED25519_SUPPORT == ENABLED || ED448_SUPPORT == ENABLED)
859  error_t error;
860  size_t length;
861 
862  //Check parameters
863  if(privateKey == NULL || written == NULL)
865 
866  //Invalid elliptic curve?
867  if(privateKey->curve == NULL)
869 
870  //Check output format
871  if(format == PEM_PRIVATE_KEY_FORMAT_PKCS8 ||
874  {
875  size_t n;
876  uint8_t *p;
877  int32_t version;
878  Asn1Tag tag;
879 
880  //Point to the buffer where to write the PrivateKeyInfo structure
881  p = (uint8_t *) output;
882  //Total length of the PrivateKeyInfo structure
883  length = 0;
884 
885  //The Version field identifies the version of OneAsymmetricKey. If
886  //publicKey is present, then version is set to v2 else version is set
887  //to v1 (refer to RFC 5958, section 2)
888  if(format == PEM_PRIVATE_KEY_FORMAT_PKCS8_V2 &&
889  privateKey->q.curve != NULL)
890  {
892  }
893  else
894  {
896  }
897 
898  //Format Version field
899  error = asn1WriteInt32(version, FALSE, p, &n);
900 
901  //Check status code
902  if(!error)
903  {
904  X509SubjectPublicKeyInfo publicKeyInfo;
905 
906  //Advance data pointer
907  ASN1_INC_POINTER(p, n);
908  length += n;
909 
910  //Clear the SubjectPublicKeyInfo structure
911  osMemset(&publicKeyInfo, 0, sizeof(X509SubjectPublicKeyInfo));
912 
913  //The PrivateKeyAlgorithm identifies the private-key algorithm
914  publicKeyInfo.oid.value = privateKey->curve->oid;
915  publicKeyInfo.oid.length = privateKey->curve->oidSize;
916 
917  //Format PrivateKeyAlgorithm field
918  error = x509FormatAlgoId(&publicKeyInfo, NULL, p, &n);
919  }
920 
921  //Check status code
922  if(!error)
923  {
924  //Advance data pointer
925  ASN1_INC_POINTER(p, n);
926  length += n;
927 
928  //Format PrivateKey field
929  error = pkcs8FormatEddsaPrivateKey(privateKey, p, &n);
930  }
931 
932  //Check status code
933  if(!error)
934  {
935  //Advance data pointer
936  ASN1_INC_POINTER(p, n);
937  length += n;
938 
939  //The publicKey field is optional
940  if(format == PEM_PRIVATE_KEY_FORMAT_PKCS8_V2 &&
941  privateKey->q.curve != NULL)
942  {
943  //Format publicKey field
944  error = pkcs8FormatEddsaPublicKey(&privateKey->q, p, &n);
945 
946  //Check status code
947  if(!error)
948  {
949  //Update the length of the PrivateKeyInfo structure
950  length += n;
951  }
952  }
953  }
954 
955  //Check status code
956  if(!error)
957  {
958  //The PrivateKeyInfo structure is encapsulated within a sequence
959  tag.constructed = TRUE;
962  tag.length = length;
963 
964  //Write the corresponding ASN.1 tag
965  error = asn1InsertHeader(&tag, (uint8_t *) output, &n);
966  }
967 
968  //Check status code
969  if(!error)
970  {
971  //Get the length of the PrivateKeyInfo structure
972  length = tag.totalLength;
973 
974  //Unencrypted PKCS #8 private keys are encoded using the "PRIVATE KEY"
975  //label (refer to RFC 7468, section 10)
976  error = pemEncodeFile(output, length, "PRIVATE KEY", output, written);
977  }
978  }
979  else
980  {
981  //Invalid format
982  error = ERROR_INVALID_PARAMETER;
983  }
984 
985  //Return status code
986  return error;
987 #else
988  //Not implemented
989  return ERROR_NOT_IMPLEMENTED;
990 #endif
991 }
992 
993 
994 /**
995  * @brief Export an ML-DSA public key to PEM format
996  * @param[in] publicKey ML-DSA public key
997  * @param[out] output Buffer where to store the PEM string (optional parameter)
998  * @param[out] written Length of the resulting PEM string
999  * @param[in] format Desired output format (RFC 7468 format only)
1000  * @return Error code
1001  **/
1002 
1004  char_t *output, size_t *written, PemPublicKeyFormat format)
1005 {
1006 #if (MLDSA44_SUPPORT == ENABLED || MLDSA65_SUPPORT == ENABLED || \
1007  MLDSA87_SUPPORT == ENABLED)
1008  error_t error;
1009  size_t length;
1010 
1011  //Check parameters
1012  if(publicKey == NULL || written == NULL)
1013  return ERROR_INVALID_PARAMETER;
1014 
1015  //Invalid ML-DSA parameter set?
1016  if(publicKey->level != MLDSA44_SECURITY_LEVEL &&
1017  publicKey->level != MLDSA65_SECURITY_LEVEL &&
1018  publicKey->level != MLDSA87_SECURITY_LEVEL)
1019  {
1020  return ERROR_INVALID_KEY;
1021  }
1022 
1023  //Check output format
1024  if(format == PEM_PUBLIC_KEY_FORMAT_RFC7468 ||
1026  {
1027  X509SubjectPublicKeyInfo publicKeyInfo;
1028 
1029  //The ASN.1 encoded data of the public key is the SubjectPublicKeyInfo
1030  //structure (refer to RFC 7468, section 13)
1031  osMemset(&publicKeyInfo, 0, sizeof(X509SubjectPublicKeyInfo));
1032 
1033  //ML-DSA offers parameter sets that meet three security levels
1034  if(publicKey->level == MLDSA44_SECURITY_LEVEL)
1035  {
1036  publicKeyInfo.oid.value = MLDSA44_OID;
1037  publicKeyInfo.oid.length = sizeof(MLDSA44_OID);
1038  }
1039  else if(publicKey->level == MLDSA65_SECURITY_LEVEL)
1040  {
1041  publicKeyInfo.oid.value = MLDSA65_OID;
1042  publicKeyInfo.oid.length = sizeof(MLDSA65_OID);
1043  }
1044  else
1045  {
1046  publicKeyInfo.oid.value = MLDSA87_OID;
1047  publicKeyInfo.oid.length = sizeof(MLDSA87_OID);
1048  }
1049 
1050  //Format the SubjectPublicKeyInfo structure
1051  error = x509FormatSubjectPublicKeyInfo(&publicKeyInfo, publicKey, NULL,
1052  (uint8_t *) output, &length);
1053 
1054  //Check status code
1055  if(!error)
1056  {
1057  //Public keys are encoded using the "PUBLIC KEY" label (see RFC 7468,
1058  //section 13)
1059  error = pemEncodeFile(output, length, "PUBLIC KEY", output, written);
1060  }
1061  }
1062  else
1063  {
1064  //Invalid format
1065  error = ERROR_INVALID_PARAMETER;
1066  }
1067 
1068  //Return status code
1069  return error;
1070 #else
1071  //Not implemented
1072  return ERROR_NOT_IMPLEMENTED;
1073 #endif
1074 }
1075 
1076 
1077 /**
1078  * @brief Export an ML-DSA private key to PEM format
1079  * @param[in] privateKey ML-DSA private key
1080  * @param[out] output Buffer where to store the PEM string (optional parameter)
1081  * @param[out] written Length of the resulting PEM string
1082  * @param[in] format Desired output format (PKCS #8 v1 or v2 format)
1083  * @return Error code
1084  **/
1085 
1087  char_t *output, size_t *written, PemPrivateKeyFormat format)
1088 {
1089 #if (MLDSA44_SUPPORT == ENABLED || MLDSA65_SUPPORT == ENABLED || \
1090  MLDSA87_SUPPORT == ENABLED)
1091  error_t error;
1092  size_t length;
1093 
1094  //Check parameters
1095  if(privateKey == NULL || written == NULL)
1096  return ERROR_INVALID_PARAMETER;
1097 
1098  //Invalid ML-DSA parameter set?
1099  if(privateKey->level != MLDSA44_SECURITY_LEVEL &&
1100  privateKey->level != MLDSA65_SECURITY_LEVEL &&
1101  privateKey->level != MLDSA87_SECURITY_LEVEL)
1102  {
1103  return ERROR_INVALID_KEY;
1104  }
1105 
1106  //Check output format
1107  if(format == PEM_PRIVATE_KEY_FORMAT_PKCS8 ||
1109  {
1110  size_t n;
1111  uint8_t *p;
1112  Asn1Tag tag;
1113 
1114  //Point to the buffer where to write the PrivateKeyInfo structure
1115  p = (uint8_t *) output;
1116  //Total length of the PrivateKeyInfo structure
1117  length = 0;
1118 
1119  //Format Version field
1120  error = asn1WriteInt32(PKCS8_VERSION_1, FALSE, p, &n);
1121 
1122  //Check status code
1123  if(!error)
1124  {
1125  X509SubjectPublicKeyInfo publicKeyInfo;
1126 
1127  //Advance data pointer
1128  ASN1_INC_POINTER(p, n);
1129  length += n;
1130 
1131  //Clear the SubjectPublicKeyInfo structure
1132  osMemset(&publicKeyInfo, 0, sizeof(X509SubjectPublicKeyInfo));
1133 
1134  //The PrivateKeyAlgorithm identifies the private-key algorithm
1135  if(privateKey->level == MLDSA44_SECURITY_LEVEL)
1136  {
1137  publicKeyInfo.oid.value = MLDSA44_OID;
1138  publicKeyInfo.oid.length = sizeof(MLDSA44_OID);
1139  }
1140  else if(privateKey->level == MLDSA65_SECURITY_LEVEL)
1141  {
1142  publicKeyInfo.oid.value = MLDSA65_OID;
1143  publicKeyInfo.oid.length = sizeof(MLDSA65_OID);
1144  }
1145  else
1146  {
1147  publicKeyInfo.oid.value = MLDSA87_OID;
1148  publicKeyInfo.oid.length = sizeof(MLDSA87_OID);
1149  }
1150 
1151  //Format PrivateKeyAlgorithm field
1152  error = x509FormatAlgoId(&publicKeyInfo, NULL, p, &n);
1153  }
1154 
1155  //Check status code
1156  if(!error)
1157  {
1158  //Advance data pointer
1159  ASN1_INC_POINTER(p, n);
1160  length += n;
1161 
1162  //Format PrivateKey field
1163  error = pkcs8FormatMldsaPrivateKey(privateKey, p, &n);
1164  }
1165 
1166  //Check status code
1167  if(!error)
1168  {
1169  //Update the length of the PrivateKeyInfo structure
1170  length += n;
1171 
1172  //The PrivateKeyInfo structure is encapsulated within a sequence
1173  tag.constructed = TRUE;
1176  tag.length = length;
1177 
1178  //Write the corresponding ASN.1 tag
1179  error = asn1InsertHeader(&tag, (uint8_t *) output, &n);
1180  }
1181 
1182  //Check status code
1183  if(!error)
1184  {
1185  //Get the length of the PrivateKeyInfo structure
1186  length = tag.totalLength;
1187 
1188  //Unencrypted PKCS #8 private keys are encoded using the "PRIVATE KEY"
1189  //label (refer to RFC 7468, section 10)
1190  error = pemEncodeFile(output, length, "PRIVATE KEY", output, written);
1191  }
1192  }
1193  else
1194  {
1195  //Invalid format
1196  error = ERROR_INVALID_PARAMETER;
1197  }
1198 
1199  //Return status code
1200  return error;
1201 #else
1202  //Not implemented
1203  return ERROR_NOT_IMPLEMENTED;
1204 #endif
1205 }
1206 
1207 #endif
const uint8_t MLDSA44_OID[9]
Definition: mldsa.c:47
PKCS #8 key formatting.
error_t pemExportDsaPublicKey(const DsaPublicKey *publicKey, char_t *output, size_t *written, PemPublicKeyFormat format)
Export a DSA public key to PEM format.
@ PKCS8_VERSION_2
Definition: x509_common.h:526
const uint8_t MLDSA65_OID[9]
Definition: mldsa.c:49
@ ERROR_NOT_IMPLEMENTED
Definition: error.h:66
const EcCurve * curve
Elliptic curve parameters.
Definition: eddsa.h:76
uint8_t p
Definition: ndp.h:300
error_t pemExportRsaPrivateKey(const RsaPrivateKey *privateKey, char_t *output, size_t *written, PemPrivateKeyFormat format)
Export an RSA private key to PEM format.
@ PEM_PRIVATE_KEY_FORMAT_DEFAULT
Default format.
const EcCurve * curve
Elliptic curve parameters.
Definition: ec.h:433
X509OctetString oid
Definition: x509_common.h:880
#define TRUE
Definition: os_port.h:50
error_t x509ExportEcPrivateKey(const EcCurve *curve, const EcPrivateKey *privateKey, const EcPublicKey *publicKey, uint8_t *output, size_t *written)
Export an EC private key to ASN.1 format.
error_t asn1InsertHeader(Asn1Tag *tag, uint8_t *data, size_t *written)
Insert an ASN.1 tag header.
Definition: asn1.c:643
error_t pkcs8FormatEddsaPrivateKey(const EddsaPrivateKey *privateKey, uint8_t *output, size_t *written)
Format an EdDSA private key.
const uint8_t EC_PUBLIC_KEY_OID[7]
Definition: ec.c:44
error_t pemExportMldsaPrivateKey(const MldsaPrivateKey *privateKey, char_t *output, size_t *written, PemPrivateKeyFormat format)
Export an ML-DSA private key to PEM format.
X509EcParameters ecParams
Definition: x509_common.h:891
error_t pemExportEddsaPublicKey(const EddsaPublicKey *publicKey, char_t *output, size_t *written, PemPublicKeyFormat format)
Export an EdDSA public key to PEM format.
uint_t level
Security level.
Definition: mldsa.h:95
error_t pkcs8FormatRsaPrivateKey(const RsaPrivateKey *privateKey, uint8_t *output, size_t *written)
Format an RSA private key.
#define MLDSA87_SECURITY_LEVEL
Definition: mldsa.h:61
const uint8_t RSASSA_PSS_OID[9]
Definition: rsa.c:85
@ PEM_PRIVATE_KEY_FORMAT_PKCS1
PKCS #1 format.
uint8_t version
Definition: coap_common.h:177
#define MLDSA65_SECURITY_LEVEL
Definition: mldsa.h:50
error_t pkcs8FormatDsaPrivateKey(const DsaPrivateKey *privateKey, uint8_t *output, size_t *written)
Format a DSA private key.
@ PEM_PUBLIC_KEY_FORMAT_DEFAULT
Default format.
error_t x509FormatSubjectPublicKeyInfo(const X509SubjectPublicKeyInfo *publicKeyInfo, const void *publicKey, uint8_t *keyId, uint8_t *output, size_t *written)
Format SubjectPublicKeyInfo structure.
PemPublicKeyFormat
PEM public key formats.
const uint8_t DSA_OID[7]
Definition: dsa.c:51
size_t totalLength
Definition: asn1.h:111
@ ERROR_INVALID_ELLIPTIC_CURVE
Definition: error.h:134
size_t length
Definition: asn1.h:109
#define MLDSA44_SECURITY_LEVEL
Definition: mldsa.h:39
#define FALSE
Definition: os_port.h:46
error_t pemExportRsaPublicKey(const RsaPublicKey *publicKey, char_t *output, size_t *written, PemPublicKeyFormat format)
Export an RSA public key to PEM format.
ML-DSA public key.
Definition: mldsa.h:82
DSA public key.
Definition: dsa.h:61
@ ERROR_INVALID_PARAMETER
Invalid parameter.
Definition: error.h:47
const EcCurve * curve
Elliptic curve parameters.
Definition: eddsa.h:65
error_t
Error codes.
Definition: error.h:43
EdDSA public key.
Definition: eddsa.h:64
error_t pemExportDsaPrivateKey(const DsaPrivateKey *privateKey, char_t *output, size_t *written, PemPrivateKeyFormat format)
Export a DSA private key to PEM format.
#define ASN1_CLASS_UNIVERSAL
Definition: asn1.h:52
error_t pkcs8FormatEcPrivateKey(const EcPrivateKey *privateKey, uint8_t *output, size_t *written)
Format an EC private key.
error_t x509FormatAlgoId(const X509SubjectPublicKeyInfo *publicKeyInfo, const void *params, uint8_t *output, size_t *written)
Format AlgorithmIdentifier structure.
ASN.1 tag.
Definition: asn1.h:105
#define ASN1_INC_POINTER(p, n)
Definition: asn1.h:58
error_t x509ExportRsaPublicKey(const RsaPublicKey *publicKey, uint8_t *output, size_t *written)
Export an RSA public key to ASN.1 format.
error_t pemEncodeFile(const void *input, size_t inputLen, const char_t *label, char_t *output, size_t *outputLen)
Convert ASN.1 data to PEM encoding.
Definition: pem_common.c:122
RSA public key.
Definition: rsa.h:57
error_t pemExportEddsaPrivateKey(const EddsaPrivateKey *privateKey, char_t *output, size_t *written, PemPrivateKeyFormat format)
Export an EdDSA private key to PEM format.
General definitions for cryptographic algorithms.
EcPublicKey q
Public key.
Definition: ec.h:436
EC private key.
Definition: ec.h:432
DSA private key.
Definition: dsa.h:72
@ PEM_PUBLIC_KEY_FORMAT_PKCS1
PKCS #1 format.
uint_t objClass
Definition: asn1.h:107
uint8_t length
Definition: tcp.h:375
@ PKCS8_VERSION_1
Definition: x509_common.h:525
error_t pkcs8FormatMldsaPrivateKey(const MldsaPrivateKey *privateKey, uint8_t *output, size_t *written)
Format an ML-DSA private key.
PemPrivateKeyFormat
PEM private key formats.
@ PEM_PRIVATE_KEY_FORMAT_PKCS8
PKCS #8 v1 format.
error_t x509ExportRsaPrivateKey(const RsaPrivateKey *privateKey, uint8_t *output, size_t *written)
Export an RSA private key to ASN.1 format.
@ PEM_PUBLIC_KEY_FORMAT_RFC7468
RFC 7468 format.
X509OctetString namedCurve
Definition: x509_common.h:849
EdDSA private key.
Definition: eddsa.h:75
const uint8_t RSA_ENCRYPTION_OID[9]
Definition: rsa.c:54
EC public key.
Definition: ec.h:421
char char_t
Definition: compiler_port.h:55
Formatting of ASN.1 encoded keys.
error_t pemExportRsaPssPublicKey(const RsaPublicKey *publicKey, char_t *output, size_t *written, PemPublicKeyFormat format)
Export an RSA-PSS public key to PEM format.
@ PEM_PRIVATE_KEY_FORMAT_PKCS8_V2
PKCS #8 v2 format.
uint8_t n
RSA private key.
Definition: rsa.h:68
Subject Public Key Information extension.
Definition: x509_common.h:878
error_t pemExportMldsaPublicKey(const MldsaPublicKey *publicKey, char_t *output, size_t *written, PemPublicKeyFormat format)
Export an ML-DSA public key to PEM format.
error_t pemExportRsaPssPrivateKey(const RsaPrivateKey *privateKey, char_t *output, size_t *written, PemPrivateKeyFormat format)
Export an RSA-PSS private key to PEM format.
bool_t constructed
Definition: asn1.h:106
ML-DSA private key.
Definition: mldsa.h:94
@ ASN1_TYPE_SEQUENCE
Definition: asn1.h:83
EddsaPublicKey q
Public key.
Definition: eddsa.h:79
DsaDomainParameters params
DSA domain parameters.
Definition: dsa.h:73
error_t pemExportEcPrivateKey(const EcPrivateKey *privateKey, char_t *output, size_t *written, PemPrivateKeyFormat format)
Export an EC private key to PEM format.
const uint8_t * value
Definition: x509_common.h:732
error_t pemExportEcPublicKey(const EcPublicKey *publicKey, char_t *output, size_t *written, PemPublicKeyFormat format)
Export an EC public key to PEM format.
error_t pkcs8FormatEddsaPublicKey(const EddsaPublicKey *publicKey, uint8_t *output, size_t *written)
Format an EdDSA public key.
const uint8_t MLDSA87_OID[9]
Definition: mldsa.c:51
uint_t level
Security level.
Definition: mldsa.h:83
#define osMemset(p, value, length)
Definition: os_port.h:141
@ PEM_PRIVATE_KEY_FORMAT_RFC5915
RFC 5915 format.
error_t asn1WriteInt32(int32_t value, bool_t reverse, uint8_t *data, size_t *written)
Write a 32-bit integer to the output stream.
Definition: asn1.c:781
const EcCurve * curve
Elliptic curve parameters.
Definition: ec.h:422
PEM key file export functions.
@ ERROR_INVALID_KEY
Definition: error.h:106
Debugging facilities.
uint_t objType
Definition: asn1.h:108
ASN.1 (Abstract Syntax Notation One)