2 * Copyright 1995-2021 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
);
34 static int gendh_cb(EVP_PKEY_CTX
*ctx
);
36 typedef enum OPTION_choice
{
37 OPT_ERR
= -1, OPT_EOF
= 0, OPT_HELP
,
38 OPT_INFORM
, OPT_OUTFORM
, OPT_IN
, OPT_OUT
,
39 OPT_ENGINE
, OPT_CHECK
, OPT_TEXT
, OPT_NOOUT
,
40 OPT_DSAPARAM
, OPT_2
, OPT_3
, OPT_5
,
41 OPT_R_ENUM
, OPT_PROV_ENUM
44 const OPTIONS dhparam_options
[] = {
45 {OPT_HELP_STR
, 1, '-', "Usage: %s [options] [numbits]\n"},
47 OPT_SECTION("General"),
48 {"help", OPT_HELP
, '-', "Display this summary"},
49 {"check", OPT_CHECK
, '-', "Check the DH parameters"},
50 #if !defined(OPENSSL_NO_DSA) || !defined(OPENSSL_NO_DEPRECATED_3_0)
51 {"dsaparam", OPT_DSAPARAM
, '-',
52 "Read or generate DSA parameters, convert to DH"},
54 #ifndef OPENSSL_NO_ENGINE
55 {"engine", OPT_ENGINE
, 's', "Use engine e, possibly a hardware device"},
59 {"in", OPT_IN
, '<', "Input file"},
60 {"inform", OPT_INFORM
, 'F', "Input format, DER or PEM"},
62 OPT_SECTION("Output"),
63 {"out", OPT_OUT
, '>', "Output file"},
64 {"outform", OPT_OUTFORM
, 'F', "Output format, DER or PEM"},
65 {"text", OPT_TEXT
, '-', "Print a text form of the DH parameters"},
66 {"noout", OPT_NOOUT
, '-', "Don't output any DH parameters"},
67 {"2", OPT_2
, '-', "Generate parameters using 2 as the generator value"},
68 {"3", OPT_3
, '-', "Generate parameters using 3 as the generator value"},
69 {"5", OPT_5
, '-', "Generate parameters using 5 as the generator value"},
75 {"numbits", 0, 0, "Number of bits if generating parameters (optional)"},
79 int dhparam_main(int argc
, char **argv
)
81 BIO
*in
= NULL
, *out
= NULL
;
82 EVP_PKEY
*pkey
= NULL
, *tmppkey
= NULL
;
83 EVP_PKEY_CTX
*ctx
= NULL
;
84 char *infile
= NULL
, *outfile
= NULL
, *prog
;
87 int text
= 0, ret
= 1, num
= 0, g
= 0;
88 int informat
= FORMAT_PEM
, outformat
= FORMAT_PEM
, check
= 0, noout
= 0;
91 prog
= opt_init(argc
, argv
, dhparam_options
);
92 while ((o
= opt_next()) != OPT_EOF
) {
97 BIO_printf(bio_err
, "%s: Use -help for summary.\n", prog
);
100 opt_help(dhparam_options
);
104 if (!opt_format(opt_arg(), OPT_FMT_PEMDER
, &informat
))
108 if (!opt_format(opt_arg(), OPT_FMT_PEMDER
, &outformat
))
118 e
= setup_engine(opt_arg(), 0);
146 if (!opt_provider(o
))
152 /* One optional argument, bitsize to generate. */
153 argc
= opt_num_rest();
156 if (!opt_int(argv
[0], &num
) || num
<= 0)
158 } else if (argc
!= 0) {
169 "Error, generator may not be chosen for DSA parameters\n");
173 out
= bio_open_default(outfile
, 'w', outformat
);
182 const char *alg
= dsaparam
? "DSA" : "DH";
184 ctx
= EVP_PKEY_CTX_new_from_name(NULL
, alg
, NULL
);
187 "Error, %s param generation context allocation failed\n",
191 EVP_PKEY_CTX_set_cb(ctx
, gendh_cb
);
192 EVP_PKEY_CTX_set_app_data(ctx
, bio_err
);
194 "Generating %s parameters, %d bit long %sprime\n",
195 alg
, num
, dsaparam
? "" : "safe ");
197 if (!EVP_PKEY_paramgen_init(ctx
)) {
199 "Error, unable to initialise %s parameters\n",
205 if (!EVP_PKEY_CTX_set_dsa_paramgen_bits(ctx
, num
)) {
206 BIO_printf(bio_err
, "Error, unable to set DSA prime length\n");
210 if (!EVP_PKEY_CTX_set_dh_paramgen_prime_len(ctx
, num
)) {
211 BIO_printf(bio_err
, "Error, unable to set DH prime length\n");
214 if (!EVP_PKEY_CTX_set_dh_paramgen_generator(ctx
, g
)) {
215 BIO_printf(bio_err
, "Error, unable to set generator\n");
220 if (!EVP_PKEY_paramgen(ctx
, &tmppkey
)) {
221 BIO_printf(bio_err
, "Error, %s generation failed\n", alg
);
225 EVP_PKEY_CTX_free(ctx
);
228 pkey
= dsa_to_dh(tmppkey
);
231 EVP_PKEY_free(tmppkey
);
237 OSSL_DECODER_CTX
*decoderctx
= NULL
;
238 const char *keytype
= "DH";
241 in
= bio_open_default(infile
, 'r', informat
);
247 * We assume we're done unless we explicitly want to retry and set
252 * We set NULL for the keytype to allow any key type. We don't know
253 * if we're going to get DH or DHX (or DSA in the event of dsaparam).
254 * We check that we got one of those key types afterwards.
257 = OSSL_DECODER_CTX_new_for_pkey(&tmppkey
,
258 (informat
== FORMAT_ASN1
)
261 (informat
== FORMAT_ASN1
)
263 OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS
,
266 if (decoderctx
!= NULL
267 && !OSSL_DECODER_from_bio(decoderctx
, in
)
268 && informat
== FORMAT_ASN1
269 && strcmp(keytype
, "DH") == 0) {
271 * When reading DER we explicitly state the expected keytype
272 * because, unlike PEM, there is no header to declare what
273 * the contents of the DER file are. The decoders just try
274 * and guess. Unfortunately with DHX key types they may guess
275 * wrong and think we have a DSA keytype. Therefore we try
276 * both DH and DHX sequentially.
280 * BIO_reset() returns 0 for success for file BIOs only!!!
281 * This won't work for stdin (and never has done)
282 * TODO: We should fix this at some point
284 if (BIO_reset(in
) == 0)
287 OSSL_DECODER_CTX_free(decoderctx
);
289 if (tmppkey
== NULL
) {
290 BIO_printf(bio_err
, "Error, unable to load parameters\n");
295 if (!EVP_PKEY_is_a(tmppkey
, "DSA")) {
296 BIO_printf(bio_err
, "Error, unable to load DSA parameters\n");
299 pkey
= dsa_to_dh(tmppkey
);
303 if (!EVP_PKEY_is_a(tmppkey
, "DH")
304 && !EVP_PKEY_is_a(tmppkey
, "DHX")) {
305 BIO_printf(bio_err
, "Error, unable to load DH parameters\n");
314 EVP_PKEY_print_params(out
, pkey
, 4, NULL
);
317 ctx
= EVP_PKEY_CTX_new_from_pkey(NULL
, pkey
, NULL
);
319 BIO_printf(bio_err
, "Error, failed to check DH parameters\n");
322 if (!EVP_PKEY_param_check(ctx
)) {
323 BIO_printf(bio_err
, "Error, invalid parameters generated\n");
326 BIO_printf(bio_err
, "DH parameters appear to be ok.\n");
330 OSSL_ENCODER_CTX
*ectx
=
331 OSSL_ENCODER_CTX_new_for_pkey(pkey
,
332 OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS
,
333 outformat
== FORMAT_ASN1
337 if (ectx
== NULL
|| !OSSL_ENCODER_to_bio(ectx
, out
)) {
338 OSSL_ENCODER_CTX_free(ectx
);
339 BIO_printf(bio_err
, "Error, unable to write DH parameters\n");
342 OSSL_ENCODER_CTX_free(ectx
);
347 ERR_print_errors(bio_err
);
351 EVP_PKEY_free(tmppkey
);
352 EVP_PKEY_CTX_free(ctx
);
358 * Historically we had the low level call DSA_dup_DH() to do this.
359 * That is now deprecated with no replacement. Since we still need to do this
360 * for backwards compatibility reasons, we do it "manually".
362 static EVP_PKEY
*dsa_to_dh(EVP_PKEY
*dh
)
364 OSSL_PARAM_BLD
*tmpl
= NULL
;
365 OSSL_PARAM
*params
= NULL
;
366 BIGNUM
*bn_p
= NULL
, *bn_q
= NULL
, *bn_g
= NULL
;
367 EVP_PKEY_CTX
*ctx
= NULL
;
368 EVP_PKEY
*pkey
= NULL
;
370 if (!EVP_PKEY_get_bn_param(dh
, OSSL_PKEY_PARAM_FFC_P
, &bn_p
)
371 || !EVP_PKEY_get_bn_param(dh
, OSSL_PKEY_PARAM_FFC_Q
, &bn_q
)
372 || !EVP_PKEY_get_bn_param(dh
, OSSL_PKEY_PARAM_FFC_G
, &bn_g
)) {
373 BIO_printf(bio_err
, "Error, failed to set DH parameters\n");
377 if ((tmpl
= OSSL_PARAM_BLD_new()) == NULL
378 || !OSSL_PARAM_BLD_push_BN(tmpl
, OSSL_PKEY_PARAM_FFC_P
,
380 || !OSSL_PARAM_BLD_push_BN(tmpl
, OSSL_PKEY_PARAM_FFC_Q
,
382 || !OSSL_PARAM_BLD_push_BN(tmpl
, OSSL_PKEY_PARAM_FFC_G
,
384 || (params
= OSSL_PARAM_BLD_to_param(tmpl
)) == NULL
) {
385 BIO_printf(bio_err
, "Error, failed to set DH parameters\n");
389 ctx
= EVP_PKEY_CTX_new_from_name(NULL
, "DHX", NULL
);
391 || !EVP_PKEY_fromdata_init(ctx
)
392 || !EVP_PKEY_fromdata(ctx
, &pkey
, EVP_PKEY_KEY_PARAMETERS
, params
)) {
393 BIO_printf(bio_err
, "Error, failed to set DH parameters\n");
398 EVP_PKEY_CTX_free(ctx
);
399 OSSL_PARAM_free(params
);
400 OSSL_PARAM_BLD_free(tmpl
);
407 static int gendh_cb(EVP_PKEY_CTX
*ctx
)
409 int p
= EVP_PKEY_CTX_get_keygen_info(ctx
, 0);
410 BIO
*b
= EVP_PKEY_CTX_get_app_data(ctx
);
411 static const char symbols
[] = ".+*\n";
412 char c
= (p
>= 0 && (size_t)p
< sizeof(symbols
) - 1) ? symbols
[p
] : '?';