1 /*
2  *  Key writing application
3  *
4  *  Copyright The Mbed TLS Contributors
5  *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
6  */
7 
8 #include "mbedtls/build_info.h"
9 
10 #include "mbedtls/platform.h"
11 
12 #if defined(MBEDTLS_PK_PARSE_C) && defined(MBEDTLS_PK_WRITE_C) && \
13     defined(MBEDTLS_FS_IO) && \
14     defined(MBEDTLS_ENTROPY_C) && defined(MBEDTLS_CTR_DRBG_C)
15 #include "mbedtls/error.h"
16 #include "mbedtls/pk.h"
17 #include "mbedtls/error.h"
18 
19 #include "mbedtls/entropy.h"
20 #include "mbedtls/ctr_drbg.h"
21 
22 #include <stdio.h>
23 #include <string.h>
24 #endif
25 
26 #if defined(MBEDTLS_PEM_WRITE_C)
27 #define USAGE_OUT \
28     "    output_file=%%s      default: keyfile.pem\n"   \
29     "    output_format=pem|der default: pem\n"
30 #else
31 #define USAGE_OUT \
32     "    output_file=%%s      default: keyfile.der\n"   \
33     "    output_format=der     default: der\n"
34 #endif
35 
36 #if defined(MBEDTLS_PEM_WRITE_C)
37 #define DFL_OUTPUT_FILENAME     "keyfile.pem"
38 #define DFL_OUTPUT_FORMAT       OUTPUT_FORMAT_PEM
39 #else
40 #define DFL_OUTPUT_FILENAME     "keyfile.der"
41 #define DFL_OUTPUT_FORMAT       OUTPUT_FORMAT_DER
42 #endif
43 
44 #define DFL_MODE                MODE_NONE
45 #define DFL_FILENAME            "keyfile.key"
46 #define DFL_DEBUG_LEVEL         0
47 #define DFL_OUTPUT_MODE         OUTPUT_MODE_NONE
48 
49 #define MODE_NONE               0
50 #define MODE_PRIVATE            1
51 #define MODE_PUBLIC             2
52 
53 #define OUTPUT_MODE_NONE               0
54 #define OUTPUT_MODE_PRIVATE            1
55 #define OUTPUT_MODE_PUBLIC             2
56 
57 #define OUTPUT_FORMAT_PEM              0
58 #define OUTPUT_FORMAT_DER              1
59 
60 #define USAGE \
61     "\n usage: key_app_writer param=<>...\n"            \
62     "\n acceptable parameters:\n"                       \
63     "    mode=private|public default: none\n"           \
64     "    filename=%%s         default: keyfile.key\n"   \
65     "    output_mode=private|public default: none\n"    \
66     USAGE_OUT                                           \
67     "\n"
68 
69 #if !defined(MBEDTLS_PK_PARSE_C) || \
70     !defined(MBEDTLS_PK_WRITE_C) || \
71     !defined(MBEDTLS_FS_IO)      || \
72     !defined(MBEDTLS_ENTROPY_C)  || \
73     !defined(MBEDTLS_CTR_DRBG_C)
main(void)74 int main(void)
75 {
76     mbedtls_printf("MBEDTLS_PK_PARSE_C and/or MBEDTLS_PK_WRITE_C and/or "
77                    "MBEDTLS_ENTROPY_C and/or MBEDTLS_CTR_DRBG_C and/or "
78                    "MBEDTLS_FS_IO not defined.\n");
79     mbedtls_exit(0);
80 }
81 #else
82 
83 
84 /*
85  * global options
86  */
87 struct options {
88     int mode;                   /* the mode to run the application in   */
89     const char *filename;       /* filename of the key file             */
90     int output_mode;            /* the output mode to use               */
91     const char *output_file;    /* where to store the constructed key file  */
92     int output_format;          /* the output format to use             */
93 } opt;
94 
write_public_key(mbedtls_pk_context * key,const char * output_file)95 static int write_public_key(mbedtls_pk_context *key, const char *output_file)
96 {
97     int ret;
98     FILE *f;
99     unsigned char output_buf[16000];
100     unsigned char *c = output_buf;
101     size_t len = 0;
102 
103     memset(output_buf, 0, 16000);
104 
105 #if defined(MBEDTLS_PEM_WRITE_C)
106     if (opt.output_format == OUTPUT_FORMAT_PEM) {
107         if ((ret = mbedtls_pk_write_pubkey_pem(key, output_buf, 16000)) != 0) {
108             return ret;
109         }
110 
111         len = strlen((char *) output_buf);
112     } else
113 #endif
114     {
115         if ((ret = mbedtls_pk_write_pubkey_der(key, output_buf, 16000)) < 0) {
116             return ret;
117         }
118 
119         len = ret;
120         c = output_buf + sizeof(output_buf) - len;
121     }
122 
123     if ((f = fopen(output_file, "w")) == NULL) {
124         return -1;
125     }
126 
127     if (fwrite(c, 1, len, f) != len) {
128         fclose(f);
129         return -1;
130     }
131 
132     fclose(f);
133 
134     return 0;
135 }
136 
write_private_key(mbedtls_pk_context * key,const char * output_file)137 static int write_private_key(mbedtls_pk_context *key, const char *output_file)
138 {
139     int ret;
140     FILE *f;
141     unsigned char output_buf[16000];
142     unsigned char *c = output_buf;
143     size_t len = 0;
144 
145     memset(output_buf, 0, 16000);
146 
147 #if defined(MBEDTLS_PEM_WRITE_C)
148     if (opt.output_format == OUTPUT_FORMAT_PEM) {
149         if ((ret = mbedtls_pk_write_key_pem(key, output_buf, 16000)) != 0) {
150             return ret;
151         }
152 
153         len = strlen((char *) output_buf);
154     } else
155 #endif
156     {
157         if ((ret = mbedtls_pk_write_key_der(key, output_buf, 16000)) < 0) {
158             return ret;
159         }
160 
161         len = ret;
162         c = output_buf + sizeof(output_buf) - len;
163     }
164 
165     if ((f = fopen(output_file, "w")) == NULL) {
166         return -1;
167     }
168 
169     if (fwrite(c, 1, len, f) != len) {
170         fclose(f);
171         return -1;
172     }
173 
174     fclose(f);
175 
176     return 0;
177 }
178 
main(int argc,char * argv[])179 int main(int argc, char *argv[])
180 {
181     int ret = 1;
182     int exit_code = MBEDTLS_EXIT_FAILURE;
183 #if defined(MBEDTLS_ERROR_C)
184     char buf[200];
185 #endif
186     int i;
187     char *p, *q;
188 
189     const char *pers = "pkey/key_app";
190     mbedtls_entropy_context entropy;
191     mbedtls_ctr_drbg_context ctr_drbg;
192 
193     mbedtls_pk_context key;
194 #if defined(MBEDTLS_RSA_C)
195     mbedtls_mpi N, P, Q, D, E, DP, DQ, QP;
196 #endif /* MBEDTLS_RSA_C */
197 
198     /*
199      * Set to sane values
200      */
201     mbedtls_entropy_init(&entropy);
202     mbedtls_ctr_drbg_init(&ctr_drbg);
203 
204     mbedtls_pk_init(&key);
205 #if defined(MBEDTLS_ERROR_C)
206     memset(buf, 0, sizeof(buf));
207 #endif
208 
209 #if defined(MBEDTLS_USE_PSA_CRYPTO)
210     psa_status_t status = psa_crypto_init();
211     if (status != PSA_SUCCESS) {
212         mbedtls_fprintf(stderr, "Failed to initialize PSA Crypto implementation: %d\n",
213                         (int) status);
214         goto exit;
215     }
216 #endif /* MBEDTLS_USE_PSA_CRYPTO */
217 
218 #if defined(MBEDTLS_RSA_C)
219     mbedtls_mpi_init(&N); mbedtls_mpi_init(&P); mbedtls_mpi_init(&Q);
220     mbedtls_mpi_init(&D); mbedtls_mpi_init(&E); mbedtls_mpi_init(&DP);
221     mbedtls_mpi_init(&DQ); mbedtls_mpi_init(&QP);
222 #endif /* MBEDTLS_RSA_C */
223 
224     if (argc < 2) {
225 usage:
226         mbedtls_printf(USAGE);
227         goto exit;
228     }
229 
230     opt.mode                = DFL_MODE;
231     opt.filename            = DFL_FILENAME;
232     opt.output_mode         = DFL_OUTPUT_MODE;
233     opt.output_file         = DFL_OUTPUT_FILENAME;
234     opt.output_format       = DFL_OUTPUT_FORMAT;
235 
236     for (i = 1; i < argc; i++) {
237         p = argv[i];
238         if ((q = strchr(p, '=')) == NULL) {
239             goto usage;
240         }
241         *q++ = '\0';
242 
243         if (strcmp(p, "mode") == 0) {
244             if (strcmp(q, "private") == 0) {
245                 opt.mode = MODE_PRIVATE;
246             } else if (strcmp(q, "public") == 0) {
247                 opt.mode = MODE_PUBLIC;
248             } else {
249                 goto usage;
250             }
251         } else if (strcmp(p, "output_mode") == 0) {
252             if (strcmp(q, "private") == 0) {
253                 opt.output_mode = OUTPUT_MODE_PRIVATE;
254             } else if (strcmp(q, "public") == 0) {
255                 opt.output_mode = OUTPUT_MODE_PUBLIC;
256             } else {
257                 goto usage;
258             }
259         } else if (strcmp(p, "output_format") == 0) {
260 #if defined(MBEDTLS_PEM_WRITE_C)
261             if (strcmp(q, "pem") == 0) {
262                 opt.output_format = OUTPUT_FORMAT_PEM;
263             } else
264 #endif
265             if (strcmp(q, "der") == 0) {
266                 opt.output_format = OUTPUT_FORMAT_DER;
267             } else {
268                 goto usage;
269             }
270         } else if (strcmp(p, "filename") == 0) {
271             opt.filename = q;
272         } else if (strcmp(p, "output_file") == 0) {
273             opt.output_file = q;
274         } else {
275             goto usage;
276         }
277     }
278 
279     if (opt.mode == MODE_NONE && opt.output_mode != OUTPUT_MODE_NONE) {
280         mbedtls_printf("\nCannot output a key without reading one.\n");
281         goto exit;
282     }
283 
284     if (opt.mode == MODE_PUBLIC && opt.output_mode == OUTPUT_MODE_PRIVATE) {
285         mbedtls_printf("\nCannot output a private key from a public key.\n");
286         goto exit;
287     }
288 
289     if (opt.mode == MODE_PRIVATE) {
290         /*
291          * 1.1. Load the key
292          */
293         mbedtls_printf("\n  . Loading the private key ...");
294         fflush(stdout);
295 
296         if ((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
297                                          (const unsigned char *) pers,
298                                          strlen(pers))) != 0) {
299             mbedtls_printf(" failed\n  !  mbedtls_ctr_drbg_seed returned -0x%04x\n",
300                            (unsigned int) -ret);
301             goto exit;
302         }
303 
304         ret = mbedtls_pk_parse_keyfile(&key, opt.filename, NULL,
305                                        mbedtls_ctr_drbg_random, &ctr_drbg);
306         if (ret != 0) {
307             mbedtls_printf(" failed\n  !  mbedtls_pk_parse_keyfile returned -0x%04x",
308                            (unsigned int) -ret);
309             goto exit;
310         }
311 
312         mbedtls_printf(" ok\n");
313 
314         /*
315          * 1.2 Print the key
316          */
317         mbedtls_printf("  . Key information    ...\n");
318 
319 #if defined(MBEDTLS_RSA_C)
320         if (mbedtls_pk_get_type(&key) == MBEDTLS_PK_RSA) {
321             mbedtls_rsa_context *rsa = mbedtls_pk_rsa(key);
322 
323             if ((ret = mbedtls_rsa_export(rsa, &N, &P, &Q, &D, &E)) != 0 ||
324                 (ret = mbedtls_rsa_export_crt(rsa, &DP, &DQ, &QP))      != 0) {
325                 mbedtls_printf(" failed\n  ! could not export RSA parameters\n\n");
326                 goto exit;
327             }
328 
329             mbedtls_mpi_write_file("N:  ",  &N,  16, NULL);
330             mbedtls_mpi_write_file("E:  ",  &E,  16, NULL);
331             mbedtls_mpi_write_file("D:  ",  &D,  16, NULL);
332             mbedtls_mpi_write_file("P:  ",  &P,  16, NULL);
333             mbedtls_mpi_write_file("Q:  ",  &Q,  16, NULL);
334             mbedtls_mpi_write_file("DP: ",  &DP, 16, NULL);
335             mbedtls_mpi_write_file("DQ:  ", &DQ, 16, NULL);
336             mbedtls_mpi_write_file("QP:  ", &QP, 16, NULL);
337         } else
338 #endif
339 #if defined(MBEDTLS_ECP_C)
340         if (mbedtls_pk_get_type(&key) == MBEDTLS_PK_ECKEY) {
341             mbedtls_ecp_keypair *ecp = mbedtls_pk_ec(key);
342             mbedtls_mpi_write_file("Q(X): ", &ecp->MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(X), 16, NULL);
343             mbedtls_mpi_write_file("Q(Y): ", &ecp->MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(Y), 16, NULL);
344             mbedtls_mpi_write_file("Q(Z): ", &ecp->MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(Z), 16, NULL);
345             mbedtls_mpi_write_file("D   : ", &ecp->MBEDTLS_PRIVATE(d), 16, NULL);
346         } else
347 #endif
348         mbedtls_printf("key type not supported yet\n");
349 
350     } else if (opt.mode == MODE_PUBLIC) {
351         /*
352          * 1.1. Load the key
353          */
354         mbedtls_printf("\n  . Loading the public key ...");
355         fflush(stdout);
356 
357         ret = mbedtls_pk_parse_public_keyfile(&key, opt.filename);
358 
359         if (ret != 0) {
360             mbedtls_printf(" failed\n  !  mbedtls_pk_parse_public_key returned -0x%04x",
361                            (unsigned int) -ret);
362             goto exit;
363         }
364 
365         mbedtls_printf(" ok\n");
366 
367         /*
368          * 1.2 Print the key
369          */
370         mbedtls_printf("  . Key information    ...\n");
371 
372 #if defined(MBEDTLS_RSA_C)
373         if (mbedtls_pk_get_type(&key) == MBEDTLS_PK_RSA) {
374             mbedtls_rsa_context *rsa = mbedtls_pk_rsa(key);
375 
376             if ((ret = mbedtls_rsa_export(rsa, &N, NULL, NULL,
377                                           NULL, &E)) != 0) {
378                 mbedtls_printf(" failed\n  ! could not export RSA parameters\n\n");
379                 goto exit;
380             }
381             mbedtls_mpi_write_file("N: ", &N, 16, NULL);
382             mbedtls_mpi_write_file("E: ", &E, 16, NULL);
383         } else
384 #endif
385 #if defined(MBEDTLS_ECP_C)
386         if (mbedtls_pk_get_type(&key) == MBEDTLS_PK_ECKEY) {
387             mbedtls_ecp_keypair *ecp = mbedtls_pk_ec(key);
388             mbedtls_mpi_write_file("Q(X): ", &ecp->MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(X), 16, NULL);
389             mbedtls_mpi_write_file("Q(Y): ", &ecp->MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(Y), 16, NULL);
390             mbedtls_mpi_write_file("Q(Z): ", &ecp->MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(Z), 16, NULL);
391         } else
392 #endif
393         mbedtls_printf("key type not supported yet\n");
394     } else {
395         goto usage;
396     }
397 
398     if (opt.output_mode == OUTPUT_MODE_PUBLIC) {
399         write_public_key(&key, opt.output_file);
400     }
401     if (opt.output_mode == OUTPUT_MODE_PRIVATE) {
402         write_private_key(&key, opt.output_file);
403     }
404 
405     exit_code = MBEDTLS_EXIT_SUCCESS;
406 
407 exit:
408 
409     if (exit_code != MBEDTLS_EXIT_SUCCESS) {
410 #ifdef MBEDTLS_ERROR_C
411         mbedtls_strerror(ret, buf, sizeof(buf));
412         mbedtls_printf(" - %s\n", buf);
413 #else
414         mbedtls_printf("\n");
415 #endif
416     }
417 
418 #if defined(MBEDTLS_RSA_C)
419     mbedtls_mpi_free(&N); mbedtls_mpi_free(&P); mbedtls_mpi_free(&Q);
420     mbedtls_mpi_free(&D); mbedtls_mpi_free(&E); mbedtls_mpi_free(&DP);
421     mbedtls_mpi_free(&DQ); mbedtls_mpi_free(&QP);
422 #endif /* MBEDTLS_RSA_C */
423 
424     mbedtls_pk_free(&key);
425 
426     mbedtls_ctr_drbg_free(&ctr_drbg);
427     mbedtls_entropy_free(&entropy);
428 #if defined(MBEDTLS_USE_PSA_CRYPTO)
429     mbedtls_psa_crypto_free();
430 #endif /* MBEDTLS_USE_PSA_CRYPTO */
431 
432     mbedtls_exit(exit_code);
433 }
434 #endif /* MBEDTLS_PK_PARSE_C && MBEDTLS_PK_WRITE_C && MBEDTLS_FS_IO &&
435           MBEDTLS_ENTROPY_C && MBEDTLS_CTR_DRBG_C */
436