Generate, Check and Convert DH Parameters with OpenSSL
You will finish with a DH parameter file that OpenSSL can read, a repeatable validation check, and a safe PEM-to-DER conversion. The workflow uses openssl dhparam, supplied by the openssl package.
The route
Jump straight to the step you need, or tick off Done means at the end.
Allow a few minutes for a small test set and potentially much longer for a production-sized set. You need a shell and write access to a working directory. The command does not need root for files in your home directory. Use elevated privileges only when the final destination is deliberately owned by a system service.
Version note: the local manpage is labelled OpenSSL 3.0.13, while the executable used for these checks reports OpenSSL 3.6.1. The documented options below are present in both references. Confirm your own binary with openssl version before relying on version-specific behaviour.
1. Check the executable and choose a private working path
Start by confirming which OpenSSL will run and make a directory that is not a shared service directory:
$ command -v openssl
/home/linuxbrew/.linuxbrew/bin/openssl
$ openssl version
OpenSSL 3.6.1 27 Jan 2026
$ mkdir -p "$HOME/dhparam-work"
$ cd "$HOME/dhparam-work"
Your path and version may differ. Keep generated material out of a directory that a daemon reads automatically until it has passed the checks below.
Checkpoint
You are in a disposable working directory and know which binary is being used.
2. Generate a test parameter set
Generate a 512-bit set with generator 2 and write it as the default PEM format:
$ openssl dhparam -2 -out dh-test.pem 512
Generating DH parameters, 512 bit long safe prime
...generation progress varies...
The bit count must be the final argument. For example, placing 512 before -out is rejected by the installed OpenSSL because numbits is positional and must be last. The minimum documented length is 512 bits and the maximum is 10000 bits.
This 512-bit file is useful for a quick local smoke test only. Do not deploy it for a real DH exchange. For an operational choice, follow the requirements of the application and its current cryptographic guidance. If no generator is supplied, the documented default is generator 2. If a generator is supplied without a bit count, the default length is 2048 bits, which can take considerably longer to generate.
Generation is CPU work and produces a new file. If a file with the same name already exists, stop and inspect it before running the command again. Do not use the input and output path as the same file when manipulating parameters.
Checkpoint
Confirm that the file exists and is not empty:
$ test -s dh-test.pem && echo "parameter file created"
parameter file created
$ sed -n '1,2p' dh-test.pem
-----BEGIN DH PARAMETERS-----
3. Validate the parameters before use
Run the built-in checks and suppress the encoded parameter output:
$ openssl dhparam -in dh-test.pem -check -noout
DH parameters appear to be ok.
A zero exit status and the confirmation message are the expected result for the test file. -check examines the supplied parameters and can report warnings for invalid input. -noout keeps the PEM block out of the terminal, which is useful in logs and automation.
Check the exit status immediately when scripting:
if openssl dhparam -in dh-test.pem -check -noout; then
echo "DH parameters passed validation"
else
echo "DH parameter validation failed" >&2
exit 1
fi
Do not treat a readable file as a valid parameter set. A file can exist, have the expected PEM header and still fail cryptographic validation.
4. Inspect the values without changing the file
Use -text with -noout when you need a human-readable view:
$ openssl dhparam -in dh-test.pem -text -noout
DH Parameters: (512 bit)
P:
...hexadecimal value...
G: 2 (0x2)
The modulus is deliberately abbreviated above because its exact value is randomly generated. Inspecting it does not modify the file. Avoid copying the full value into tickets or logs unless there is a clear operational reason; parameter files are public inputs in many protocols, but unnecessary disclosure still creates clutter and handling risk.
5. Convert a verified file to DER
PEM is text-wrapped and convenient for administration. DER is binary and may be required by another tool. Convert to a different output path:
$ openssl dhparam -in dh-test.pem -outform DER -out dh-test.der
$ file dh-test.der
dh-test.der: data
$ openssl dhparam -inform DER -in dh-test.der -check -noout
DH parameters appear to be ok.
The input format defaults to PEM, and the output format defaults to PEM. State the format explicitly when a file crosses a tool or host boundary. The DER check proves that this conversion can be read back by the same command.
Warning
Do not set -out to the same filename as -in. The manpage explicitly warns against that operation. If you need to replace a file in a controlled deployment, write a new file, validate it, set its ownership and permissions, then use the service's documented reload or replacement procedure. Keep the old file until the consumer has been tested so rollback is possible.
6. Avoid the DSA-style shortcut without understanding its trade-off
The optional -dsaparam mode generates or reads DSA-style parameters and converts them to DH format. It is faster and uses a shorter recommended private exponent, but the manpage warns that a fresh DH key should be created for every use to avoid possible small-subgroup attacks. That is a protocol and key-lifecycle requirement, not a performance toggle to add casually. For the ordinary workflow above, leave -dsaparam out and use the strong-prime DH generation.
Similarly, -2, -3 and -5 select the generator. They cause input to be ignored and parameters to be generated, so do not combine one of them with an input filename expecting the existing file to be checked.
Done means
openssl versionidentified the executable you intended to use.- The generated file is in a deliberate working or deployment location and was not overwritten accidentally.
openssl dhparam -in FILE -check -nooutreturned success.- You know whether each file is PEM or DER and have checked the format when converting.
- You have not treated the 512-bit smoke-test example as a production security setting.