1 /* $OpenBSD: dhparam.c,v 1.19 2025/01/19 10:24:17 tb Exp $ */ 2 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 3 * All rights reserved. 4 * 5 * This package is an SSL implementation written 6 * by Eric Young (eay@cryptsoft.com). 7 * The implementation was written so as to conform with Netscapes SSL. 8 * 9 * This library is free for commercial and non-commercial use as long as 10 * the following conditions are aheared to. The following conditions 11 * apply to all code found in this distribution, be it the RC4, RSA, 12 * lhash, DES, etc., code; not just the SSL code. The SSL documentation 13 * included with this distribution is covered by the same copyright terms 14 * except that the holder is Tim Hudson (tjh@cryptsoft.com). 15 * 16 * Copyright remains Eric Young's, and as such any Copyright notices in 17 * the code are not to be removed. 18 * If this package is used in a product, Eric Young should be given attribution 19 * as the author of the parts of the library used. 20 * This can be in the form of a textual message at program startup or 21 * in documentation (online or textual) provided with the package. 22 * 23 * Redistribution and use in source and binary forms, with or without 24 * modification, are permitted provided that the following conditions 25 * are met: 26 * 1. Redistributions of source code must retain the copyright 27 * notice, this list of conditions and the following disclaimer. 28 * 2. Redistributions in binary form must reproduce the above copyright 29 * notice, this list of conditions and the following disclaimer in the 30 * documentation and/or other materials provided with the distribution. 31 * 3. All advertising materials mentioning features or use of this software 32 * must display the following acknowledgement: 33 * "This product includes cryptographic software written by 34 * Eric Young (eay@cryptsoft.com)" 35 * The word 'cryptographic' can be left out if the rouines from the library 36 * being used are not cryptographic related :-). 37 * 4. If you include any Windows specific code (or a derivative thereof) from 38 * the apps directory (application code) you must include an acknowledgement: 39 * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" 40 * 41 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND 42 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 43 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 44 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 45 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 46 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 47 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 49 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 50 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 51 * SUCH DAMAGE. 52 * 53 * The licence and distribution terms for any publically available version or 54 * derivative of this code cannot be changed. i.e. this code cannot simply be 55 * copied and put under another distribution licence 56 * [including the GNU Public Licence.] 57 */ 58 /* ==================================================================== 59 * Copyright (c) 1998-2000 The OpenSSL Project. All rights reserved. 60 * 61 * Redistribution and use in source and binary forms, with or without 62 * modification, are permitted provided that the following conditions 63 * are met: 64 * 65 * 1. Redistributions of source code must retain the above copyright 66 * notice, this list of conditions and the following disclaimer. 67 * 68 * 2. Redistributions in binary form must reproduce the above copyright 69 * notice, this list of conditions and the following disclaimer in 70 * the documentation and/or other materials provided with the 71 * distribution. 72 * 73 * 3. All advertising materials mentioning features or use of this 74 * software must display the following acknowledgment: 75 * "This product includes software developed by the OpenSSL Project 76 * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" 77 * 78 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 79 * endorse or promote products derived from this software without 80 * prior written permission. For written permission, please contact 81 * openssl-core@openssl.org. 82 * 83 * 5. Products derived from this software may not be called "OpenSSL" 84 * nor may "OpenSSL" appear in their names without prior written 85 * permission of the OpenSSL Project. 86 * 87 * 6. Redistributions of any form whatsoever must retain the following 88 * acknowledgment: 89 * "This product includes software developed by the OpenSSL Project 90 * for use in the OpenSSL Toolkit (http://www.openssl.org/)" 91 * 92 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 93 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 94 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 95 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 96 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 97 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 98 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 99 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 100 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 101 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 102 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 103 * OF THE POSSIBILITY OF SUCH DAMAGE. 104 * ==================================================================== 105 * 106 * This product includes cryptographic software written by Eric Young 107 * (eay@cryptsoft.com). This product includes software written by Tim 108 * Hudson (tjh@cryptsoft.com). 109 * 110 */ 111 112 #include <openssl/opensslconf.h> /* for OPENSSL_NO_DH */ 113 114 #ifndef OPENSSL_NO_DH 115 116 #include <stdio.h> 117 #include <stdlib.h> 118 #include <string.h> 119 #include <time.h> 120 121 #include "apps.h" 122 123 #include <openssl/bio.h> 124 #include <openssl/bn.h> 125 #include <openssl/err.h> 126 #include <openssl/dh.h> 127 #include <openssl/pem.h> 128 #include <openssl/x509.h> 129 130 #include <openssl/dsa.h> 131 132 #define DEFBITS 2048 133 134 static struct { 135 int check; 136 int dsaparam; 137 int g; 138 char *infile; 139 int informat; 140 int noout; 141 char *outfile; 142 int outformat; 143 int text; 144 } cfg; 145 146 static const struct option dhparam_options[] = { 147 { 148 .name = "2", 149 .desc = "Generate DH parameters with a generator value of 2 " 150 "(default)", 151 .type = OPTION_VALUE, 152 .opt.value = &cfg.g, 153 .value = 2, 154 }, 155 { 156 .name = "5", 157 .desc = "Generate DH parameters with a generator value of 5", 158 .type = OPTION_VALUE, 159 .opt.value = &cfg.g, 160 .value = 5, 161 }, 162 { 163 .name = "check", 164 .desc = "Check the DH parameters", 165 .type = OPTION_FLAG, 166 .opt.flag = &cfg.check, 167 }, 168 { 169 .name = "dsaparam", 170 .desc = "Read or generate DSA parameters and convert to DH", 171 .type = OPTION_FLAG, 172 .opt.flag = &cfg.dsaparam, 173 }, 174 { 175 .name = "in", 176 .argname = "file", 177 .desc = "Input file (default stdin)", 178 .type = OPTION_ARG, 179 .opt.arg = &cfg.infile, 180 }, 181 { 182 .name = "inform", 183 .argname = "format", 184 .desc = "Input format (DER or PEM (default))", 185 .type = OPTION_ARG_FORMAT, 186 .opt.value = &cfg.informat, 187 }, 188 { 189 .name = "noout", 190 .desc = "Do not output encoded version of DH parameters", 191 .type = OPTION_FLAG, 192 .opt.flag = &cfg.noout, 193 }, 194 { 195 .name = "out", 196 .argname = "file", 197 .desc = "Output file (default stdout)", 198 .type = OPTION_ARG, 199 .opt.arg = &cfg.outfile, 200 }, 201 { 202 .name = "outform", 203 .argname = "format", 204 .desc = "Output format (DER or PEM (default))", 205 .type = OPTION_ARG_FORMAT, 206 .opt.value = &cfg.outformat, 207 }, 208 { 209 .name = "text", 210 .desc = "Print DH parameters in plain text", 211 .type = OPTION_FLAG, 212 .opt.flag = &cfg.text, 213 }, 214 { NULL }, 215 }; 216 217 static void 218 dhparam_usage(void) 219 { 220 fprintf(stderr, 221 "usage: dhparam [-2 | -5] [-check] [-dsaparam]\n" 222 " [-in file] [-inform DER | PEM] [-noout] [-out file]\n" 223 " [-outform DER | PEM] [-text] [numbits]\n\n"); 224 options_usage(dhparam_options); 225 } 226 227 static int dh_cb(int p, int n, BN_GENCB *cb); 228 229 int 230 dhparam_main(int argc, char **argv) 231 { 232 BIO *in = NULL, *out = NULL; 233 BN_GENCB *cb = NULL; 234 char *num_bits = NULL; 235 DH *dh = NULL; 236 int num = 0; 237 int ret = 1; 238 int i; 239 240 if (pledge("stdio cpath wpath rpath", NULL) == -1) { 241 perror("pledge"); 242 exit(1); 243 } 244 245 memset(&cfg, 0, sizeof(cfg)); 246 247 cfg.informat = FORMAT_PEM; 248 cfg.outformat = FORMAT_PEM; 249 250 if (options_parse(argc, argv, dhparam_options, &num_bits, NULL) != 0) { 251 dhparam_usage(); 252 return (1); 253 } 254 255 if (num_bits != NULL) { 256 if(sscanf(num_bits, "%d", &num) == 0 || num <= 0) { 257 BIO_printf(bio_err, "invalid number of bits: %s\n", 258 num_bits); 259 return (1); 260 } 261 } 262 263 if (cfg.g && !num) 264 num = DEFBITS; 265 266 if (cfg.dsaparam) { 267 if (cfg.g) { 268 BIO_printf(bio_err, "generator may not be chosen for DSA parameters\n"); 269 goto end; 270 } 271 } else { 272 /* DH parameters */ 273 if (num && !cfg.g) 274 cfg.g = 2; 275 } 276 277 if (num) { 278 if ((cb = BN_GENCB_new()) == NULL) { 279 BIO_printf(bio_err, 280 "Error allocating BN_GENCB object\n"); 281 goto end; 282 } 283 284 BN_GENCB_set(cb, dh_cb, bio_err); 285 if (cfg.dsaparam) { 286 DSA *dsa = DSA_new(); 287 288 BIO_printf(bio_err, "Generating DSA parameters, %d bit long prime\n", num); 289 if (!dsa || !DSA_generate_parameters_ex(dsa, num, 290 NULL, 0, NULL, NULL, cb)) { 291 DSA_free(dsa); 292 ERR_print_errors(bio_err); 293 goto end; 294 } 295 dh = DSA_dup_DH(dsa); 296 DSA_free(dsa); 297 if (dh == NULL) { 298 ERR_print_errors(bio_err); 299 goto end; 300 } 301 } else { 302 dh = DH_new(); 303 BIO_printf(bio_err, "Generating DH parameters, %d bit long safe prime, generator %d\n", num, cfg.g); 304 BIO_printf(bio_err, "This is going to take a long time\n"); 305 if (!dh || !DH_generate_parameters_ex(dh, num, cfg.g, cb)) { 306 ERR_print_errors(bio_err); 307 goto end; 308 } 309 } 310 } else { 311 312 in = BIO_new(BIO_s_file()); 313 if (in == NULL) { 314 ERR_print_errors(bio_err); 315 goto end; 316 } 317 if (cfg.infile == NULL) 318 BIO_set_fp(in, stdin, BIO_NOCLOSE); 319 else { 320 if (BIO_read_filename(in, cfg.infile) <= 0) { 321 perror(cfg.infile); 322 goto end; 323 } 324 } 325 326 if (cfg.informat != FORMAT_ASN1 && 327 cfg.informat != FORMAT_PEM) { 328 BIO_printf(bio_err, "bad input format specified\n"); 329 goto end; 330 } 331 if (cfg.dsaparam) { 332 DSA *dsa; 333 334 if (cfg.informat == FORMAT_ASN1) 335 dsa = d2i_DSAparams_bio(in, NULL); 336 else /* informat == FORMAT_PEM */ 337 dsa = PEM_read_bio_DSAparams(in, NULL, NULL, NULL); 338 339 if (dsa == NULL) { 340 BIO_printf(bio_err, "unable to load DSA parameters\n"); 341 ERR_print_errors(bio_err); 342 goto end; 343 } 344 dh = DSA_dup_DH(dsa); 345 DSA_free(dsa); 346 if (dh == NULL) { 347 ERR_print_errors(bio_err); 348 goto end; 349 } 350 } else 351 { 352 if (cfg.informat == FORMAT_ASN1) 353 dh = d2i_DHparams_bio(in, NULL); 354 else /* informat == FORMAT_PEM */ 355 dh = PEM_read_bio_DHparams(in, NULL, NULL, NULL); 356 357 if (dh == NULL) { 358 BIO_printf(bio_err, "unable to load DH parameters\n"); 359 ERR_print_errors(bio_err); 360 goto end; 361 } 362 } 363 364 /* dh != NULL */ 365 } 366 367 out = BIO_new(BIO_s_file()); 368 if (out == NULL) { 369 ERR_print_errors(bio_err); 370 goto end; 371 } 372 if (cfg.outfile == NULL) { 373 BIO_set_fp(out, stdout, BIO_NOCLOSE); 374 } else { 375 if (BIO_write_filename(out, cfg.outfile) <= 0) { 376 perror(cfg.outfile); 377 goto end; 378 } 379 } 380 381 382 if (cfg.text) { 383 DHparams_print(out, dh); 384 } 385 if (cfg.check) { 386 if (!DH_check(dh, &i)) { 387 ERR_print_errors(bio_err); 388 goto end; 389 } 390 if (i & DH_CHECK_P_NOT_PRIME) 391 printf("p value is not prime\n"); 392 if (i & DH_CHECK_P_NOT_SAFE_PRIME) 393 printf("p value is not a safe prime\n"); 394 if (i & DH_UNABLE_TO_CHECK_GENERATOR) 395 printf("unable to check the generator value\n"); 396 if (i & DH_NOT_SUITABLE_GENERATOR) 397 printf("the g value is not a generator\n"); 398 if (i == 0) 399 printf("DH parameters appear to be ok.\n"); 400 } 401 if (!cfg.noout) { 402 if (cfg.outformat == FORMAT_ASN1) 403 i = i2d_DHparams_bio(out, dh); 404 else if (cfg.outformat == FORMAT_PEM) 405 i = PEM_write_bio_DHparams(out, dh); 406 else { 407 BIO_printf(bio_err, "bad output format specified for outfile\n"); 408 goto end; 409 } 410 if (!i) { 411 BIO_printf(bio_err, "unable to write DH parameters\n"); 412 ERR_print_errors(bio_err); 413 goto end; 414 } 415 } 416 ret = 0; 417 418 end: 419 BIO_free(in); 420 BIO_free_all(out); 421 BN_GENCB_free(cb); 422 DH_free(dh); 423 424 return (ret); 425 } 426 427 /* dh_cb is identical to dsa_cb in apps/dsaparam.c */ 428 static int 429 dh_cb(int p, int n, BN_GENCB *cb) 430 { 431 char c = '*'; 432 433 if (p == 0) 434 c = '.'; 435 if (p == 1) 436 c = '+'; 437 if (p == 2) 438 c = '*'; 439 if (p == 3) 440 c = '\n'; 441 BIO_write(BN_GENCB_get_arg(cb), &c, 1); 442 (void) BIO_flush(BN_GENCB_get_arg(cb)); 443 return 1; 444 } 445 446 #endif 447