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