2 * Copyright 1995-2023 The OpenSSL Project Authors. All Rights Reserved.
4 * Licensed under the Apache License 2.0 (the "License"). You may not use
5 * this file except in compliance with the License. You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
10 #include <openssl/opensslconf.h>
18 #include <openssl/bio.h>
19 #include <openssl/err.h>
20 #include <openssl/bn.h>
21 #include <openssl/dsa.h>
22 #include <openssl/dh.h>
23 #include <openssl/x509.h>
24 #include <openssl/pem.h>
25 #include <openssl/core_names.h>
26 #include <openssl/core_dispatch.h>
27 #include <openssl/param_build.h>
28 #include <openssl/encoder.h>
29 #include <openssl/decoder.h>
33 static EVP_PKEY
*dsa_to_dh(EVP_PKEY
*dh
);
35 static int verbose
= 1;
37 typedef enum OPTION_choice
{
39 OPT_INFORM
, OPT_OUTFORM
, OPT_IN
, OPT_OUT
,
40 OPT_ENGINE
, OPT_CHECK
, OPT_TEXT
, OPT_NOOUT
,
41 OPT_DSAPARAM
, OPT_2
, OPT_3
, OPT_5
, OPT_VERBOSE
, OPT_QUIET
,
42 OPT_R_ENUM
, OPT_PROV_ENUM
45 const OPTIONS dhparam_options
[] = {
46 {OPT_HELP_STR
, 1, '-', "Usage: %s [options] [numbits]\n"},
48 OPT_SECTION("General"),
49 {"help", OPT_HELP
, '-', "Display this summary"},
50 {"check", OPT_CHECK
, '-', "Check the DH parameters"},
51 #if !defined(OPENSSL_NO_DSA) || !defined(OPENSSL_NO_DEPRECATED_3_0)
52 {"dsaparam", OPT_DSAPARAM
, '-',
53 "Read or generate DSA parameters, convert to DH"},
55 #ifndef OPENSSL_NO_ENGINE
56 {"engine", OPT_ENGINE
, 's', "Use engine e, possibly a hardware device"},
60 {"in", OPT_IN
, '<', "Input file"},
61 {"inform", OPT_INFORM
, 'F', "Input format, DER or PEM"},
63 OPT_SECTION("Output"),
64 {"out", OPT_OUT
, '>', "Output file"},
65 {"outform", OPT_OUTFORM
, 'F', "Output format, DER or PEM"},
66 {"text", OPT_TEXT
, '-', "Print a text form of the DH parameters"},
67 {"noout", OPT_NOOUT
, '-', "Don't output any DH parameters"},
68 {"2", OPT_2
, '-', "Generate parameters using 2 as the generator value"},
69 {"3", OPT_3
, '-', "Generate parameters using 3 as the generator value"},
70 {"5", OPT_5
, '-', "Generate parameters using 5 as the generator value"},
71 {"verbose", OPT_VERBOSE
, '-', "Verbose output"},
72 {"quiet", OPT_QUIET
, '-', "Terse output"},
78 {"numbits", 0, 0, "Number of bits if generating parameters (optional)"},
82 int dhparam_main(int argc
, char **argv
)
84 BIO
*in
= NULL
, *out
= NULL
;
85 EVP_PKEY
*pkey
= NULL
, *tmppkey
= NULL
;
86 EVP_PKEY_CTX
*ctx
= NULL
;
87 char *infile
= NULL
, *outfile
= NULL
, *prog
;
90 int text
= 0, ret
= 1, num
= 0, g
= 0;
91 int informat
= FORMAT_PEM
, outformat
= FORMAT_PEM
, check
= 0, noout
= 0;
94 prog
= opt_init(argc
, argv
, dhparam_options
);
95 while ((o
= opt_next()) != OPT_EOF
) {
100 BIO_printf(bio_err
, "%s: Use -help for summary.\n", prog
);
103 opt_help(dhparam_options
);
107 if (!opt_format(opt_arg(), OPT_FMT_PEMDER
, &informat
))
111 if (!opt_format(opt_arg(), OPT_FMT_PEMDER
, &outformat
))
121 e
= setup_engine(opt_arg(), 0);
155 if (!opt_provider(o
))
161 /* One optional argument, bitsize to generate. */
162 argc
= opt_num_rest();
165 if (!opt_int(argv
[0], &num
) || num
<= 0)
167 } else if (!opt_check_rest_arg(NULL
)) {
170 if (!app_RAND_load())
178 "Error, generator may not be chosen for DSA parameters\n");
187 const char *alg
= dsaparam
? "DSA" : "DH";
189 if (infile
!= NULL
) {
190 BIO_printf(bio_err
, "Warning, input file %s ignored\n", infile
);
193 ctx
= EVP_PKEY_CTX_new_from_name(app_get0_libctx(), alg
, app_get0_propq());
196 "Error, %s param generation context allocation failed\n",
200 EVP_PKEY_CTX_set_app_data(ctx
, bio_err
);
202 EVP_PKEY_CTX_set_cb(ctx
, progress_cb
);
204 "Generating %s parameters, %d bit long %sprime\n",
205 alg
, num
, dsaparam
? "" : "safe ");
208 if (EVP_PKEY_paramgen_init(ctx
) <= 0) {
210 "Error, unable to initialise %s parameters\n",
216 if (EVP_PKEY_CTX_set_dsa_paramgen_bits(ctx
, num
) <= 0) {
217 BIO_printf(bio_err
, "Error, unable to set DSA prime length\n");
221 if (EVP_PKEY_CTX_set_dh_paramgen_prime_len(ctx
, num
) <= 0) {
222 BIO_printf(bio_err
, "Error, unable to set DH prime length\n");
225 if (EVP_PKEY_CTX_set_dh_paramgen_generator(ctx
, g
) <= 0) {
226 BIO_printf(bio_err
, "Error, unable to set generator\n");
231 tmppkey
= app_paramgen(ctx
, alg
);
234 EVP_PKEY_CTX_free(ctx
);
237 pkey
= dsa_to_dh(tmppkey
);
240 EVP_PKEY_free(tmppkey
);
246 OSSL_DECODER_CTX
*decoderctx
= NULL
;
247 const char *keytype
= "DH";
250 in
= bio_open_default(infile
, 'r', informat
);
256 * We assume we're done unless we explicitly want to retry and set
261 * We set NULL for the keytype to allow any key type. We don't know
262 * if we're going to get DH or DHX (or DSA in the event of dsaparam).
263 * We check that we got one of those key types afterwards.
266 = OSSL_DECODER_CTX_new_for_pkey(&tmppkey
,
267 (informat
== FORMAT_ASN1
)
270 (informat
== FORMAT_ASN1
)
272 OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS
,
275 if (decoderctx
!= NULL
276 && !OSSL_DECODER_from_bio(decoderctx
, in
)
277 && informat
== FORMAT_ASN1
278 && strcmp(keytype
, "DH") == 0) {
280 * When reading DER we explicitly state the expected keytype
281 * because, unlike PEM, there is no header to declare what
282 * the contents of the DER file are. The decoders just try
283 * and guess. Unfortunately with DHX key types they may guess
284 * wrong and think we have a DSA keytype. Therefore, we try
285 * both DH and DHX sequentially.
289 * BIO_reset() returns 0 for success for file BIOs only!!!
290 * This won't work for stdin (and never has done)
292 if (BIO_reset(in
) == 0)
295 OSSL_DECODER_CTX_free(decoderctx
);
297 if (tmppkey
== NULL
) {
298 BIO_printf(bio_err
, "Error, unable to load parameters\n");
303 if (!EVP_PKEY_is_a(tmppkey
, "DSA")) {
304 BIO_printf(bio_err
, "Error, unable to load DSA parameters\n");
307 pkey
= dsa_to_dh(tmppkey
);
311 if (!EVP_PKEY_is_a(tmppkey
, "DH")
312 && !EVP_PKEY_is_a(tmppkey
, "DHX")) {
313 BIO_printf(bio_err
, "Error, unable to load DH parameters\n");
321 out
= bio_open_default(outfile
, 'w', outformat
);
326 EVP_PKEY_print_params(out
, pkey
, 4, NULL
);
329 ctx
= EVP_PKEY_CTX_new_from_pkey(app_get0_libctx(), pkey
, app_get0_propq());
331 BIO_printf(bio_err
, "Error, failed to check DH parameters\n");
334 if (EVP_PKEY_param_check(ctx
) <= 0) {
335 BIO_printf(bio_err
, "Error, invalid parameters generated\n");
338 BIO_printf(bio_err
, "DH parameters appear to be ok.\n");
342 OSSL_ENCODER_CTX
*ectx
=
343 OSSL_ENCODER_CTX_new_for_pkey(pkey
,
344 OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS
,
345 outformat
== FORMAT_ASN1
349 if (ectx
== NULL
|| !OSSL_ENCODER_to_bio(ectx
, out
)) {
350 OSSL_ENCODER_CTX_free(ectx
);
351 BIO_printf(bio_err
, "Error, unable to write DH parameters\n");
354 OSSL_ENCODER_CTX_free(ectx
);
359 ERR_print_errors(bio_err
);
363 EVP_PKEY_free(tmppkey
);
364 EVP_PKEY_CTX_free(ctx
);
370 * Historically we had the low-level call DSA_dup_DH() to do this.
371 * That is now deprecated with no replacement. Since we still need to do this
372 * for backwards compatibility reasons, we do it "manually".
374 static EVP_PKEY
*dsa_to_dh(EVP_PKEY
*dh
)
376 OSSL_PARAM_BLD
*tmpl
= NULL
;
377 OSSL_PARAM
*params
= NULL
;
378 BIGNUM
*bn_p
= NULL
, *bn_q
= NULL
, *bn_g
= NULL
;
379 EVP_PKEY_CTX
*ctx
= NULL
;
380 EVP_PKEY
*pkey
= NULL
;
382 if (!EVP_PKEY_get_bn_param(dh
, OSSL_PKEY_PARAM_FFC_P
, &bn_p
)
383 || !EVP_PKEY_get_bn_param(dh
, OSSL_PKEY_PARAM_FFC_Q
, &bn_q
)
384 || !EVP_PKEY_get_bn_param(dh
, OSSL_PKEY_PARAM_FFC_G
, &bn_g
)) {
385 BIO_printf(bio_err
, "Error, failed to set DH parameters\n");
389 if ((tmpl
= OSSL_PARAM_BLD_new()) == NULL
390 || !OSSL_PARAM_BLD_push_BN(tmpl
, OSSL_PKEY_PARAM_FFC_P
,
392 || !OSSL_PARAM_BLD_push_BN(tmpl
, OSSL_PKEY_PARAM_FFC_Q
,
394 || !OSSL_PARAM_BLD_push_BN(tmpl
, OSSL_PKEY_PARAM_FFC_G
,
396 || (params
= OSSL_PARAM_BLD_to_param(tmpl
)) == NULL
) {
397 BIO_printf(bio_err
, "Error, failed to set DH parameters\n");
401 ctx
= EVP_PKEY_CTX_new_from_name(app_get0_libctx(), "DHX", app_get0_propq());
403 || EVP_PKEY_fromdata_init(ctx
) <= 0
404 || EVP_PKEY_fromdata(ctx
, &pkey
, EVP_PKEY_KEY_PARAMETERS
, params
) <= 0) {
405 BIO_printf(bio_err
, "Error, failed to set DH parameters\n");
410 EVP_PKEY_CTX_free(ctx
);
411 OSSL_PARAM_free(params
);
412 OSSL_PARAM_BLD_free(tmpl
);