xref: /third_party/mbedtls/programs/pkey/gen_key.c (revision a8e1175b)
1/*
2 *  Key generation 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_WRITE_C) || !defined(MBEDTLS_PEM_WRITE_C) ||    \
13    !defined(MBEDTLS_FS_IO) || !defined(MBEDTLS_ENTROPY_C) ||           \
14    !defined(MBEDTLS_CTR_DRBG_C) || !defined(MBEDTLS_BIGNUM_C)
15int main(void)
16{
17    mbedtls_printf("MBEDTLS_PK_WRITE_C and/or MBEDTLS_FS_IO and/or "
18                   "MBEDTLS_ENTROPY_C and/or MBEDTLS_CTR_DRBG_C and/or "
19                   "MBEDTLS_PEM_WRITE_C and/or MBEDTLS_BIGNUM_C "
20                   "not defined.\n");
21    mbedtls_exit(0);
22}
23#else
24
25#include "mbedtls/error.h"
26#include "mbedtls/pk.h"
27#include "mbedtls/ecdsa.h"
28#include "mbedtls/rsa.h"
29#include "mbedtls/error.h"
30#include "mbedtls/entropy.h"
31#include "mbedtls/ctr_drbg.h"
32
33#include <stdio.h>
34#include <stdlib.h>
35#include <string.h>
36
37#if !defined(_WIN32)
38#include <unistd.h>
39
40#define DEV_RANDOM_THRESHOLD        32
41
42int dev_random_entropy_poll(void *data, unsigned char *output,
43                            size_t len, size_t *olen)
44{
45    FILE *file;
46    size_t ret, left = len;
47    unsigned char *p = output;
48    ((void) data);
49
50    *olen = 0;
51
52    file = fopen("/dev/random", "rb");
53    if (file == NULL) {
54        return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
55    }
56
57    while (left > 0) {
58        /* /dev/random can return much less than requested. If so, try again */
59        ret = fread(p, 1, left, file);
60        if (ret == 0 && ferror(file)) {
61            fclose(file);
62            return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
63        }
64
65        p += ret;
66        left -= ret;
67        sleep(1);
68    }
69    fclose(file);
70    *olen = len;
71
72    return 0;
73}
74#endif /* !_WIN32 */
75
76#if defined(MBEDTLS_ECP_C)
77#define DFL_EC_CURVE            mbedtls_ecp_curve_list()->grp_id
78#else
79#define DFL_EC_CURVE            0
80#endif
81
82#if !defined(_WIN32) && defined(MBEDTLS_FS_IO)
83#define USAGE_DEV_RANDOM \
84    "    use_dev_random=0|1    default: 0\n"
85#else
86#define USAGE_DEV_RANDOM ""
87#endif /* !_WIN32 && MBEDTLS_FS_IO */
88
89#define FORMAT_PEM              0
90#define FORMAT_DER              1
91
92#define DFL_TYPE                MBEDTLS_PK_RSA
93#define DFL_RSA_KEYSIZE         4096
94#define DFL_FILENAME            "keyfile.key"
95#define DFL_FORMAT              FORMAT_PEM
96#define DFL_USE_DEV_RANDOM      0
97
98#define USAGE \
99    "\n usage: gen_key param=<>...\n"                   \
100    "\n acceptable parameters:\n"                       \
101    "    type=rsa|ec           default: rsa\n"          \
102    "    rsa_keysize=%%d        default: 4096\n"        \
103    "    ec_curve=%%s           see below\n"            \
104    "    filename=%%s           default: keyfile.key\n" \
105    "    format=pem|der        default: pem\n"          \
106    USAGE_DEV_RANDOM                                    \
107    "\n"
108
109
110/*
111 * global options
112 */
113struct options {
114    int type;                   /* the type of key to generate          */
115    int rsa_keysize;            /* length of key in bits                */
116    int ec_curve;               /* curve identifier for EC keys         */
117    const char *filename;       /* filename of the key file             */
118    int format;                 /* the output format to use             */
119    int use_dev_random;         /* use /dev/random as entropy source    */
120} opt;
121
122static int write_private_key(mbedtls_pk_context *key, const char *output_file)
123{
124    int ret;
125    FILE *f;
126    unsigned char output_buf[16000];
127    unsigned char *c = output_buf;
128    size_t len = 0;
129
130    memset(output_buf, 0, 16000);
131    if (opt.format == FORMAT_PEM) {
132        if ((ret = mbedtls_pk_write_key_pem(key, output_buf, 16000)) != 0) {
133            return ret;
134        }
135
136        len = strlen((char *) output_buf);
137    } else {
138        if ((ret = mbedtls_pk_write_key_der(key, output_buf, 16000)) < 0) {
139            return ret;
140        }
141
142        len = ret;
143        c = output_buf + sizeof(output_buf) - len;
144    }
145
146    if ((f = fopen(output_file, "wb")) == NULL) {
147        return -1;
148    }
149
150    if (fwrite(c, 1, len, f) != len) {
151        fclose(f);
152        return -1;
153    }
154
155    fclose(f);
156
157    return 0;
158}
159
160#if defined(MBEDTLS_ECP_C)
161static int show_ecp_key(const mbedtls_ecp_keypair *ecp, int has_private)
162{
163    int ret = 0;
164
165    const mbedtls_ecp_curve_info *curve_info =
166        mbedtls_ecp_curve_info_from_grp_id(
167            mbedtls_ecp_keypair_get_group_id(ecp));
168    mbedtls_printf("curve: %s\n", curve_info->name);
169
170    mbedtls_ecp_group grp;
171    mbedtls_ecp_group_init(&grp);
172    mbedtls_mpi D;
173    mbedtls_mpi_init(&D);
174    mbedtls_ecp_point pt;
175    mbedtls_ecp_point_init(&pt);
176    mbedtls_mpi X, Y;
177    mbedtls_mpi_init(&X); mbedtls_mpi_init(&Y);
178
179    MBEDTLS_MPI_CHK(mbedtls_ecp_export(ecp, &grp,
180                                       (has_private ? &D : NULL),
181                                       &pt));
182
183    unsigned char point_bin[MBEDTLS_ECP_MAX_PT_LEN];
184    size_t len = 0;
185    MBEDTLS_MPI_CHK(mbedtls_ecp_point_write_binary(
186                        &grp, &pt, MBEDTLS_ECP_PF_UNCOMPRESSED,
187                        &len, point_bin, sizeof(point_bin)));
188    switch (mbedtls_ecp_get_type(&grp)) {
189        case MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS:
190            if ((len & 1) == 0 || point_bin[0] != 0x04) {
191                /* Point in an unxepected format. This shouldn't happen. */
192                ret = -1;
193                goto cleanup;
194            }
195            MBEDTLS_MPI_CHK(
196                mbedtls_mpi_read_binary(&X, point_bin + 1, len / 2));
197            MBEDTLS_MPI_CHK(
198                mbedtls_mpi_read_binary(&Y, point_bin + 1 + len / 2, len / 2));
199            mbedtls_mpi_write_file("X_Q:   ", &X, 16, NULL);
200            mbedtls_mpi_write_file("Y_Q:   ", &Y, 16, NULL);
201            break;
202        case MBEDTLS_ECP_TYPE_MONTGOMERY:
203            MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&X, point_bin, len));
204            mbedtls_mpi_write_file("X_Q:   ", &X, 16, NULL);
205            break;
206        default:
207            mbedtls_printf(
208                "This program does not yet support listing coordinates for this curve type.\n");
209            break;
210    }
211
212    if (has_private) {
213        mbedtls_mpi_write_file("D:     ", &D, 16, NULL);
214    }
215
216cleanup:
217    mbedtls_ecp_group_free(&grp);
218    mbedtls_mpi_free(&D);
219    mbedtls_ecp_point_free(&pt);
220    mbedtls_mpi_free(&X); mbedtls_mpi_free(&Y);
221    return ret;
222}
223#endif
224
225int main(int argc, char *argv[])
226{
227    int ret = 1;
228    int exit_code = MBEDTLS_EXIT_FAILURE;
229    mbedtls_pk_context key;
230    char buf[1024];
231    int i;
232    char *p, *q;
233#if defined(MBEDTLS_RSA_C)
234    mbedtls_mpi N, P, Q, D, E, DP, DQ, QP;
235#endif /* MBEDTLS_RSA_C */
236    mbedtls_entropy_context entropy;
237    mbedtls_ctr_drbg_context ctr_drbg;
238    const char *pers = "gen_key";
239#if defined(MBEDTLS_ECP_C)
240    const mbedtls_ecp_curve_info *curve_info;
241#endif
242
243    /*
244     * Set to sane values
245     */
246#if defined(MBEDTLS_RSA_C)
247    mbedtls_mpi_init(&N); mbedtls_mpi_init(&P); mbedtls_mpi_init(&Q);
248    mbedtls_mpi_init(&D); mbedtls_mpi_init(&E); mbedtls_mpi_init(&DP);
249    mbedtls_mpi_init(&DQ); mbedtls_mpi_init(&QP);
250#endif /* MBEDTLS_RSA_C */
251
252    mbedtls_entropy_init(&entropy);
253    mbedtls_pk_init(&key);
254    mbedtls_ctr_drbg_init(&ctr_drbg);
255    memset(buf, 0, sizeof(buf));
256
257#if defined(MBEDTLS_USE_PSA_CRYPTO)
258    psa_status_t status = psa_crypto_init();
259    if (status != PSA_SUCCESS) {
260        mbedtls_fprintf(stderr, "Failed to initialize PSA Crypto implementation: %d\n",
261                        (int) status);
262        goto exit;
263    }
264#endif /* MBEDTLS_USE_PSA_CRYPTO */
265
266    if (argc < 2) {
267usage:
268        mbedtls_printf(USAGE);
269#if defined(MBEDTLS_ECP_C)
270        mbedtls_printf(" available ec_curve values:\n");
271        curve_info = mbedtls_ecp_curve_list();
272        mbedtls_printf("    %s (default)\n", curve_info->name);
273        while ((++curve_info)->name != NULL) {
274            mbedtls_printf("    %s\n", curve_info->name);
275        }
276#endif /* MBEDTLS_ECP_C */
277        goto exit;
278    }
279
280    opt.type                = DFL_TYPE;
281    opt.rsa_keysize         = DFL_RSA_KEYSIZE;
282    opt.ec_curve            = DFL_EC_CURVE;
283    opt.filename            = DFL_FILENAME;
284    opt.format              = DFL_FORMAT;
285    opt.use_dev_random      = DFL_USE_DEV_RANDOM;
286
287    for (i = 1; i < argc; i++) {
288        p = argv[i];
289        if ((q = strchr(p, '=')) == NULL) {
290            goto usage;
291        }
292        *q++ = '\0';
293
294        if (strcmp(p, "type") == 0) {
295            if (strcmp(q, "rsa") == 0) {
296                opt.type = MBEDTLS_PK_RSA;
297            } else if (strcmp(q, "ec") == 0) {
298                opt.type = MBEDTLS_PK_ECKEY;
299            } else {
300                goto usage;
301            }
302        } else if (strcmp(p, "format") == 0) {
303            if (strcmp(q, "pem") == 0) {
304                opt.format = FORMAT_PEM;
305            } else if (strcmp(q, "der") == 0) {
306                opt.format = FORMAT_DER;
307            } else {
308                goto usage;
309            }
310        } else if (strcmp(p, "rsa_keysize") == 0) {
311            opt.rsa_keysize = atoi(q);
312            if (opt.rsa_keysize < 1024 ||
313                opt.rsa_keysize > MBEDTLS_MPI_MAX_BITS) {
314                goto usage;
315            }
316        }
317#if defined(MBEDTLS_ECP_C)
318        else if (strcmp(p, "ec_curve") == 0) {
319            if ((curve_info = mbedtls_ecp_curve_info_from_name(q)) == NULL) {
320                goto usage;
321            }
322            opt.ec_curve = curve_info->grp_id;
323        }
324#endif
325        else if (strcmp(p, "filename") == 0) {
326            opt.filename = q;
327        } else if (strcmp(p, "use_dev_random") == 0) {
328            opt.use_dev_random = atoi(q);
329            if (opt.use_dev_random < 0 || opt.use_dev_random > 1) {
330                goto usage;
331            }
332        } else {
333            goto usage;
334        }
335    }
336
337    mbedtls_printf("\n  . Seeding the random number generator...");
338    fflush(stdout);
339
340#if !defined(_WIN32) && defined(MBEDTLS_FS_IO)
341    if (opt.use_dev_random) {
342        if ((ret = mbedtls_entropy_add_source(&entropy, dev_random_entropy_poll,
343                                              NULL, DEV_RANDOM_THRESHOLD,
344                                              MBEDTLS_ENTROPY_SOURCE_STRONG)) != 0) {
345            mbedtls_printf(" failed\n  ! mbedtls_entropy_add_source returned -0x%04x\n",
346                           (unsigned int) -ret);
347            goto exit;
348        }
349
350        mbedtls_printf("\n    Using /dev/random, so can take a long time! ");
351        fflush(stdout);
352    }
353#endif /* !_WIN32 && MBEDTLS_FS_IO */
354
355    if ((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
356                                     (const unsigned char *) pers,
357                                     strlen(pers))) != 0) {
358        mbedtls_printf(" failed\n  ! mbedtls_ctr_drbg_seed returned -0x%04x\n",
359                       (unsigned int) -ret);
360        goto exit;
361    }
362
363    /*
364     * 1.1. Generate the key
365     */
366    mbedtls_printf("\n  . Generating the private key ...");
367    fflush(stdout);
368
369    if ((ret = mbedtls_pk_setup(&key,
370                                mbedtls_pk_info_from_type((mbedtls_pk_type_t) opt.type))) != 0) {
371        mbedtls_printf(" failed\n  !  mbedtls_pk_setup returned -0x%04x", (unsigned int) -ret);
372        goto exit;
373    }
374
375#if defined(MBEDTLS_RSA_C) && defined(MBEDTLS_GENPRIME)
376    if (opt.type == MBEDTLS_PK_RSA) {
377        ret = mbedtls_rsa_gen_key(mbedtls_pk_rsa(key), mbedtls_ctr_drbg_random, &ctr_drbg,
378                                  opt.rsa_keysize, 65537);
379        if (ret != 0) {
380            mbedtls_printf(" failed\n  !  mbedtls_rsa_gen_key returned -0x%04x",
381                           (unsigned int) -ret);
382            goto exit;
383        }
384    } else
385#endif /* MBEDTLS_RSA_C */
386#if defined(MBEDTLS_ECP_C)
387    if (opt.type == MBEDTLS_PK_ECKEY) {
388        ret = mbedtls_ecp_gen_key((mbedtls_ecp_group_id) opt.ec_curve,
389                                  mbedtls_pk_ec(key),
390                                  mbedtls_ctr_drbg_random, &ctr_drbg);
391        if (ret != 0) {
392            mbedtls_printf(" failed\n  !  mbedtls_ecp_gen_key returned -0x%04x",
393                           (unsigned int) -ret);
394            goto exit;
395        }
396    } else
397#endif /* MBEDTLS_ECP_C */
398    {
399        mbedtls_printf(" failed\n  !  key type not supported\n");
400        goto exit;
401    }
402
403    /*
404     * 1.2 Print the key
405     */
406    mbedtls_printf(" ok\n  . Key information:\n");
407
408#if defined(MBEDTLS_RSA_C)
409    if (mbedtls_pk_get_type(&key) == MBEDTLS_PK_RSA) {
410        mbedtls_rsa_context *rsa = mbedtls_pk_rsa(key);
411
412        if ((ret = mbedtls_rsa_export(rsa, &N, &P, &Q, &D, &E)) != 0 ||
413            (ret = mbedtls_rsa_export_crt(rsa, &DP, &DQ, &QP))      != 0) {
414            mbedtls_printf(" failed\n  ! could not export RSA parameters\n\n");
415            goto exit;
416        }
417
418        mbedtls_mpi_write_file("N:  ",  &N,  16, NULL);
419        mbedtls_mpi_write_file("E:  ",  &E,  16, NULL);
420        mbedtls_mpi_write_file("D:  ",  &D,  16, NULL);
421        mbedtls_mpi_write_file("P:  ",  &P,  16, NULL);
422        mbedtls_mpi_write_file("Q:  ",  &Q,  16, NULL);
423        mbedtls_mpi_write_file("DP: ",  &DP, 16, NULL);
424        mbedtls_mpi_write_file("DQ:  ", &DQ, 16, NULL);
425        mbedtls_mpi_write_file("QP:  ", &QP, 16, NULL);
426    } else
427#endif
428#if defined(MBEDTLS_ECP_C)
429    if (mbedtls_pk_get_type(&key) == MBEDTLS_PK_ECKEY) {
430        if (show_ecp_key(mbedtls_pk_ec(key), 1) != 0) {
431            mbedtls_printf(" failed\n  ! could not export ECC parameters\n\n");
432            goto exit;
433        }
434    } else
435#endif
436    mbedtls_printf("  ! key type not supported\n");
437
438    /*
439     * 1.3 Export key
440     */
441    mbedtls_printf("  . Writing key to file...");
442
443    if ((ret = write_private_key(&key, opt.filename)) != 0) {
444        mbedtls_printf(" failed\n");
445        goto exit;
446    }
447
448    mbedtls_printf(" ok\n");
449
450    exit_code = MBEDTLS_EXIT_SUCCESS;
451
452exit:
453
454    if (exit_code != MBEDTLS_EXIT_SUCCESS) {
455#ifdef MBEDTLS_ERROR_C
456        mbedtls_strerror(ret, buf, sizeof(buf));
457        mbedtls_printf(" - %s\n", buf);
458#else
459        mbedtls_printf("\n");
460#endif
461    }
462
463#if defined(MBEDTLS_RSA_C)
464    mbedtls_mpi_free(&N); mbedtls_mpi_free(&P); mbedtls_mpi_free(&Q);
465    mbedtls_mpi_free(&D); mbedtls_mpi_free(&E); mbedtls_mpi_free(&DP);
466    mbedtls_mpi_free(&DQ); mbedtls_mpi_free(&QP);
467#endif /* MBEDTLS_RSA_C */
468
469    mbedtls_pk_free(&key);
470    mbedtls_ctr_drbg_free(&ctr_drbg);
471    mbedtls_entropy_free(&entropy);
472#if defined(MBEDTLS_USE_PSA_CRYPTO)
473    mbedtls_psa_crypto_free();
474#endif /* MBEDTLS_USE_PSA_CRYPTO */
475
476    mbedtls_exit(exit_code);
477}
478#endif /* program viability conditions */
479