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