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-2025 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.5.2
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  //Any error to report?
946  if(error)
947  return error;
948 
949  //Update the length of the PrivateKeyInfo structure
950  length += n;
951  }
952  }
953 
954  //Check status code
955  if(!error)
956  {
957  //The PrivateKeyInfo structure is encapsulated within a sequence
958  tag.constructed = TRUE;
961  tag.length = length;
962 
963  //Write the corresponding ASN.1 tag
964  error = asn1InsertHeader(&tag, (uint8_t *) output, &n);
965  }
966 
967  //Check status code
968  if(!error)
969  {
970  //Get the length of the PrivateKeyInfo structure
971  length = tag.totalLength;
972 
973  //Unencrypted PKCS #8 private keys are encoded using the "PRIVATE KEY"
974  //label (refer to RFC 7468, section 10)
975  error = pemEncodeFile(output, length, "PRIVATE KEY", output, written);
976  }
977  }
978  else
979  {
980  //Invalid format
981  error = ERROR_INVALID_PARAMETER;
982  }
983 
984  //Return status code
985  return error;
986 #else
987  //Not implemented
988  return ERROR_NOT_IMPLEMENTED;
989 #endif
990 }
991 
992 #endif
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:504
@ 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:840
#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
X509EcParameters ecParams
Definition: x509_common.h:850
error_t pemExportEddsaPublicKey(const EddsaPublicKey *publicKey, char_t *output, size_t *written, PemPublicKeyFormat format)
Export an EdDSA public key to PEM format.
error_t pkcs8FormatRsaPrivateKey(const RsaPrivateKey *privateKey, uint8_t *output, size_t *written)
Format an RSA private key.
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
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 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.
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:503
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:819
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:838
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
@ 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:702
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.
#define osMemset(p, value, length)
Definition: os_port.h:138
@ 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.
Debugging facilities.
uint_t objType
Definition: asn1.h:108
ASN.1 (Abstract Syntax Notation One)