1 /*
2  *  Key generation application
3  *
4  *  Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
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  *  This file is part of mbed TLS (https://tls.mbed.org)
20  */
21 
22 #if !defined(MBEDTLS_CONFIG_FILE)
23 #include "mbedtls/config.h"
24 #else
25 #include MBEDTLS_CONFIG_FILE
26 #endif
27 
28 #if defined(MBEDTLS_PLATFORM_C)
29 #include "mbedtls/platform.h"
30 #else
31 #include <stdio.h>
32 #define mbedtls_printf     printf
33 #endif
34 
35 #if defined(MBEDTLS_PK_WRITE_C) && defined(MBEDTLS_FS_IO) && \
36     defined(MBEDTLS_ENTROPY_C) && defined(MBEDTLS_CTR_DRBG_C)
37 #include "mbedtls/error.h"
38 #include "mbedtls/pk.h"
39 #include "mbedtls/ecdsa.h"
40 #include "mbedtls/rsa.h"
41 #include "mbedtls/error.h"
42 #include "mbedtls/entropy.h"
43 #include "mbedtls/ctr_drbg.h"
44 
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 
49 #if !defined(_WIN32)
50 #include <unistd.h>
51 
52 #define DEV_RANDOM_THRESHOLD        32
53 
dev_random_entropy_poll(void * data,unsigned char * output,size_t len,size_t * olen)54 int dev_random_entropy_poll( void *data, unsigned char *output,
55                              size_t len, size_t *olen )
56 {
57     FILE *file;
58     size_t ret, left = len;
59     unsigned char *p = output;
60     ((void) data);
61 
62     *olen = 0;
63 
64     file = fopen( "/dev/random", "rb" );
65     if( file == NULL )
66         return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED );
67 
68     while( left > 0 )
69     {
70         /* /dev/random can return much less than requested. If so, try again */
71         ret = fread( p, 1, left, file );
72         if( ret == 0 && ferror( file ) )
73         {
74             fclose( file );
75             return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED );
76         }
77 
78         p += ret;
79         left -= ret;
80         sleep( 1 );
81     }
82     fclose( file );
83     *olen = len;
84 
85     return( 0 );
86 }
87 #endif /* !_WIN32 */
88 #endif
89 
90 #if defined(MBEDTLS_ECP_C)
91 #define DFL_EC_CURVE            mbedtls_ecp_curve_list()->grp_id
92 #else
93 #define DFL_EC_CURVE            0
94 #endif
95 
96 #if !defined(_WIN32) && defined(MBEDTLS_FS_IO)
97 #define USAGE_DEV_RANDOM \
98     "    use_dev_random=0|1    default: 0\n"
99 #else
100 #define USAGE_DEV_RANDOM ""
101 #endif /* !_WIN32 && MBEDTLS_FS_IO */
102 
103 #define FORMAT_PEM              0
104 #define FORMAT_DER              1
105 
106 #define DFL_TYPE                MBEDTLS_PK_RSA
107 #define DFL_RSA_KEYSIZE         4096
108 #define DFL_FILENAME            "keyfile.key"
109 #define DFL_FORMAT              FORMAT_PEM
110 #define DFL_USE_DEV_RANDOM      0
111 
112 #define USAGE \
113     "\n usage: gen_key param=<>...\n"                   \
114     "\n acceptable parameters:\n"                       \
115     "    type=rsa|ec           default: rsa\n"          \
116     "    rsa_keysize=%%d        default: 4096\n"        \
117     "    ec_curve=%%s           see below\n"            \
118     "    filename=%%s           default: keyfile.key\n" \
119     "    format=pem|der        default: pem\n"          \
120     USAGE_DEV_RANDOM                                    \
121     "\n"
122 
123 #if !defined(MBEDTLS_PK_WRITE_C) || !defined(MBEDTLS_PEM_WRITE_C) || \
124     !defined(MBEDTLS_FS_IO) || !defined(MBEDTLS_ENTROPY_C) || \
125     !defined(MBEDTLS_CTR_DRBG_C)
main(void)126 int main( void )
127 {
128     mbedtls_printf( "MBEDTLS_PK_WRITE_C and/or MBEDTLS_FS_IO and/or "
129             "MBEDTLS_ENTROPY_C and/or MBEDTLS_CTR_DRBG_C and/or "
130             "MBEDTLS_PEM_WRITE_C"
131             "not defined.\n" );
132     return( 0 );
133 }
134 #else
135 /*
136  * global options
137  */
138 struct options
139 {
140     int type;                   /* the type of key to generate          */
141     int rsa_keysize;            /* length of key in bits                */
142     int ec_curve;               /* curve identifier for EC keys         */
143     const char *filename;       /* filename of the key file             */
144     int format;                 /* the output format to use             */
145     int use_dev_random;         /* use /dev/random as entropy source    */
146 } opt;
147 
write_private_key(mbedtls_pk_context * key,const char * output_file)148 static int write_private_key( mbedtls_pk_context *key, const char *output_file )
149 {
150     int ret;
151     FILE *f;
152     unsigned char output_buf[16000];
153     unsigned char *c = output_buf;
154     size_t len = 0;
155 
156     memset(output_buf, 0, 16000);
157     if( opt.format == FORMAT_PEM )
158     {
159         if( ( ret = mbedtls_pk_write_key_pem( key, output_buf, 16000 ) ) != 0 )
160             return( ret );
161 
162         len = strlen( (char *) output_buf );
163     }
164     else
165     {
166         if( ( ret = mbedtls_pk_write_key_der( key, output_buf, 16000 ) ) < 0 )
167             return( ret );
168 
169         len = ret;
170         c = output_buf + sizeof(output_buf) - len;
171     }
172 
173     if( ( f = fopen( output_file, "wb" ) ) == NULL )
174         return( -1 );
175 
176     if( fwrite( c, 1, len, f ) != len )
177     {
178         fclose( f );
179         return( -1 );
180     }
181 
182     fclose( f );
183 
184     return( 0 );
185 }
186 
main(int argc,char * argv[])187 int main( int argc, char *argv[] )
188 {
189     int ret = 0;
190     mbedtls_pk_context key;
191     char buf[1024];
192     int i;
193     char *p, *q;
194     mbedtls_entropy_context entropy;
195     mbedtls_ctr_drbg_context ctr_drbg;
196     const char *pers = "gen_key";
197 #if defined(MBEDTLS_ECP_C)
198     const mbedtls_ecp_curve_info *curve_info;
199 #endif
200 
201     /*
202      * Set to sane values
203      */
204     mbedtls_pk_init( &key );
205     mbedtls_ctr_drbg_init( &ctr_drbg );
206     memset( buf, 0, sizeof( buf ) );
207 
208     if( argc == 0 )
209     {
210     usage:
211         ret = 1;
212         mbedtls_printf( USAGE );
213 #if defined(MBEDTLS_ECP_C)
214         mbedtls_printf( " available ec_curve values:\n" );
215         curve_info = mbedtls_ecp_curve_list();
216         mbedtls_printf( "    %s (default)\n", curve_info->name );
217         while( ( ++curve_info )->name != NULL )
218             mbedtls_printf( "    %s\n", curve_info->name );
219 #endif
220         goto exit;
221     }
222 
223     opt.type                = DFL_TYPE;
224     opt.rsa_keysize         = DFL_RSA_KEYSIZE;
225     opt.ec_curve            = DFL_EC_CURVE;
226     opt.filename            = DFL_FILENAME;
227     opt.format              = DFL_FORMAT;
228     opt.use_dev_random      = DFL_USE_DEV_RANDOM;
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, "type" ) == 0 )
238         {
239             if( strcmp( q, "rsa" ) == 0 )
240                 opt.type = MBEDTLS_PK_RSA;
241             else if( strcmp( q, "ec" ) == 0 )
242                 opt.type = MBEDTLS_PK_ECKEY;
243             else
244                 goto usage;
245         }
246         else if( strcmp( p, "format" ) == 0 )
247         {
248             if( strcmp( q, "pem" ) == 0 )
249                 opt.format = FORMAT_PEM;
250             else if( strcmp( q, "der" ) == 0 )
251                 opt.format = FORMAT_DER;
252             else
253                 goto usage;
254         }
255         else if( strcmp( p, "rsa_keysize" ) == 0 )
256         {
257             opt.rsa_keysize = atoi( q );
258             if( opt.rsa_keysize < 1024 ||
259                 opt.rsa_keysize > MBEDTLS_MPI_MAX_BITS )
260                 goto usage;
261         }
262 #if defined(MBEDTLS_ECP_C)
263         else if( strcmp( p, "ec_curve" ) == 0 )
264         {
265             if( ( curve_info = mbedtls_ecp_curve_info_from_name( q ) ) == NULL )
266                 goto usage;
267             opt.ec_curve = curve_info->grp_id;
268         }
269 #endif
270         else if( strcmp( p, "filename" ) == 0 )
271             opt.filename = q;
272         else if( strcmp( p, "use_dev_random" ) == 0 )
273         {
274             opt.use_dev_random = atoi( q );
275             if( opt.use_dev_random < 0 || opt.use_dev_random > 1 )
276                 goto usage;
277         }
278         else
279             goto usage;
280     }
281 
282     mbedtls_printf( "\n  . Seeding the random number generator..." );
283     fflush( stdout );
284 
285     mbedtls_entropy_init( &entropy );
286 #if !defined(_WIN32) && defined(MBEDTLS_FS_IO)
287     if( opt.use_dev_random )
288     {
289         if( ( ret = mbedtls_entropy_add_source( &entropy, dev_random_entropy_poll,
290                                         NULL, DEV_RANDOM_THRESHOLD,
291                                         MBEDTLS_ENTROPY_SOURCE_STRONG ) ) != 0 )
292         {
293             mbedtls_printf( " failed\n  ! mbedtls_entropy_add_source returned -0x%04x\n", -ret );
294             goto exit;
295         }
296 
297         mbedtls_printf("\n    Using /dev/random, so can take a long time! " );
298         fflush( stdout );
299     }
300 #endif /* !_WIN32 && MBEDTLS_FS_IO */
301 
302     if( ( ret = mbedtls_ctr_drbg_seed( &ctr_drbg, mbedtls_entropy_func, &entropy,
303                                (const unsigned char *) pers,
304                                strlen( pers ) ) ) != 0 )
305     {
306         mbedtls_printf( " failed\n  ! mbedtls_ctr_drbg_seed returned -0x%04x\n", -ret );
307         goto exit;
308     }
309 
310     /*
311      * 1.1. Generate the key
312      */
313     mbedtls_printf( "\n  . Generating the private key ..." );
314     fflush( stdout );
315 
316     if( ( ret = mbedtls_pk_setup( &key, mbedtls_pk_info_from_type( opt.type ) ) ) != 0 )
317     {
318         mbedtls_printf( " failed\n  !  mbedtls_pk_setup returned -0x%04x", -ret );
319         goto exit;
320     }
321 
322 #if defined(MBEDTLS_RSA_C) && defined(MBEDTLS_GENPRIME)
323     if( opt.type == MBEDTLS_PK_RSA )
324     {
325         ret = mbedtls_rsa_gen_key( mbedtls_pk_rsa( key ), mbedtls_ctr_drbg_random, &ctr_drbg,
326                            opt.rsa_keysize, 65537 );
327         if( ret != 0 )
328         {
329             mbedtls_printf( " failed\n  !  mbedtls_rsa_gen_key returned -0x%04x", -ret );
330             goto exit;
331         }
332     }
333     else
334 #endif /* MBEDTLS_RSA_C */
335 #if defined(MBEDTLS_ECP_C)
336     if( opt.type == MBEDTLS_PK_ECKEY )
337     {
338         ret = mbedtls_ecp_gen_key( opt.ec_curve, mbedtls_pk_ec( key ),
339                           mbedtls_ctr_drbg_random, &ctr_drbg );
340         if( ret != 0 )
341         {
342             mbedtls_printf( " failed\n  !  mbedtls_rsa_gen_key returned -0x%04x", -ret );
343             goto exit;
344         }
345     }
346     else
347 #endif /* MBEDTLS_ECP_C */
348     {
349         mbedtls_printf( " failed\n  !  key type not supported\n" );
350         goto exit;
351     }
352 
353     /*
354      * 1.2 Print the key
355      */
356     mbedtls_printf( " ok\n  . Key information:\n" );
357 
358 #if defined(MBEDTLS_RSA_C)
359     if( mbedtls_pk_get_type( &key ) == MBEDTLS_PK_RSA )
360     {
361         mbedtls_rsa_context *rsa = mbedtls_pk_rsa( key );
362         mbedtls_mpi_write_file( "N:  ",  &rsa->N,  16, NULL );
363         mbedtls_mpi_write_file( "E:  ",  &rsa->E,  16, NULL );
364         mbedtls_mpi_write_file( "D:  ",  &rsa->D,  16, NULL );
365         mbedtls_mpi_write_file( "P:  ",  &rsa->P,  16, NULL );
366         mbedtls_mpi_write_file( "Q:  ",  &rsa->Q,  16, NULL );
367         mbedtls_mpi_write_file( "DP: ",  &rsa->DP, 16, NULL );
368         mbedtls_mpi_write_file( "DQ:  ", &rsa->DQ, 16, NULL );
369         mbedtls_mpi_write_file( "QP:  ", &rsa->QP, 16, NULL );
370     }
371     else
372 #endif
373 #if defined(MBEDTLS_ECP_C)
374     if( mbedtls_pk_get_type( &key ) == MBEDTLS_PK_ECKEY )
375     {
376         mbedtls_ecp_keypair *ecp = mbedtls_pk_ec( key );
377         mbedtls_printf( "curve: %s\n",
378                 mbedtls_ecp_curve_info_from_grp_id( ecp->grp.id )->name );
379         mbedtls_mpi_write_file( "X_Q:   ", &ecp->Q.X, 16, NULL );
380         mbedtls_mpi_write_file( "Y_Q:   ", &ecp->Q.Y, 16, NULL );
381         mbedtls_mpi_write_file( "D:     ", &ecp->d  , 16, NULL );
382     }
383     else
384 #endif
385         mbedtls_printf("  ! key type not supported\n");
386 
387     /*
388      * 1.3 Export key
389      */
390     mbedtls_printf( "  . Writing key to file..." );
391 
392     if( ( ret = write_private_key( &key, opt.filename ) ) != 0 )
393     {
394         mbedtls_printf( " failed\n" );
395         goto exit;
396     }
397 
398     mbedtls_printf( " ok\n" );
399 
400 exit:
401 
402     if( ret != 0 && ret != 1)
403     {
404 #ifdef MBEDTLS_ERROR_C
405         mbedtls_strerror( ret, buf, sizeof( buf ) );
406         mbedtls_printf( " - %s\n", buf );
407 #else
408         mbedtls_printf("\n");
409 #endif
410     }
411 
412     mbedtls_pk_free( &key );
413     mbedtls_ctr_drbg_free( &ctr_drbg );
414     mbedtls_entropy_free( &entropy );
415 
416 #if defined(_WIN32)
417     mbedtls_printf( "  + Press Enter to exit this program.\n" );
418     fflush( stdout ); getchar();
419 #endif
420 
421     return( ret );
422 }
423 #endif /* MBEDTLS_PK_WRITE_C && MBEDTLS_PEM_WRITE_C && MBEDTLS_FS_IO &&
424         * MBEDTLS_ENTROPY_C && MBEDTLS_CTR_DRBG_C */
425 
426