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