When using SSL ciphers relying on a Diffie-Hellman key exchange, the size of the private key employed is of crucial importance for the security of that key exchange.

When I connect to a server using the openssl s_client tool. How can I query the DH parameters used?

3 Answers 3


I don't know of an easy to use command-line switch, but in the openssl s_client command line, you can add the -msg option to get an hexadecimal dump of the handshake message. Then look for the ServerKeyExchange message; it should look like this:

<<< TLS 1.2 Handshake [length 030f], ServerKeyExchange
    0c 00 03 0b 01 00 ff ff ff ff ff ff ff ff c9 0f
    da a2 21 68 c2 34 c4 c6 62 8b 80 dc 1c d1 29 02
    4e 08 8a 67 cc 74 02 0b be a6 3b 13 9b 22 51 4a

and it reads that way:

  • 0c 00 03 0b: message of type "ServerKeyExchange" (that's the "0c") of length 0x00030B bytes.
  • First element is the DH modulus as a big integer, with a two-byte length header. Here, the length is encoded as 01 00, meaning an integer encoded over 0x0100 bytes. That's 256 bytes, so the modulus has length between 2041 and 2048 bits.
  • The modulus bytes follow, in unsigned big-endian order. The top bytes of that modulus are, in this case, ff ff ff ff.... The modulus then has length exactly 2048 bits.

If you use an ECDHE cipher suite (elliptic curve), then the ServerKeyExchange format is different, of course.

See the standard for the definition of the ServerKeyExchange message. For DHE cipher suites, it contains the modulus p, generator g and server DH public key y, in that order, each expressed as a big integer in the format described above (16-bit header that contains the length in bytes, then the integer value in unsigned big-endian encoding).

Recent OpenSSL versions tend to select a DH modulus size that matches (from a security point of view) the strength of the server's key pair (used to sign the ServerKeyExchange message). In the example above, the server has a 2048-bit RSA key, so OpenSSL elected to use a 2048-bit DH modulus (in this case, the well-known modulus described in RFC 3526, section 3).

Some other servers stick to 1024-bit DH groups in order to ensure compatibility with some existing clients that do not support larger DH groups (biggest offender being the SSL implementation in Java, fixed in Java 8 build 56 in 2012). A known flaw in the TLS protocol, for the DHE cipher suites, is that the client has no way to specify what modulus size it may support (this is fixed for ECDHE, because the client can specify the exact list of curves that it accepts).

  • 1
    OpenSSL doesn't autoselect DHE, but an app callback can. OpenSSL 1.0.2 (Jan. 2015) can optionally autoselect ECDHE, and also in 1.0.2 s_client always displays "Temp server key" DH&size or ECDH&curve when applicable, just before "handshake has read x and written y", so you no longer need to decode it. It's recent Apache mod_ssl that autoselects DHE: httpd.apache.org/docs/trunk/mod/mod_ssl.html#sslcertificatefile (which notes the issue about Java clients). Commented Apr 24, 2015 at 9:18
  • I use openssl 1.0.1e and I don't get any ServerKeyExchange with 0c 00 03 0b. can you provide the exact command to get the output? I have none of the Handshakes starting with 0c
    – rubo77
    Commented Jun 9, 2015 at 14:12
  • If the cipher suite selected by the server is not a "DHE" or "ECHDE" cipher suite, then there will be no ServerKeyExchange message. Commented Jun 9, 2015 at 14:56
  • I get <<< TLS 1.2 Handshake [length 01cd], ServerKeyExchange 0c 00 01 c9 03 00 17 41 04 08 5f 82 88 1e e5 b6 followed by 443 octets which correspond to a length of 0x1c9 starting at the fifth octet. However "0300" seems to mean 768 octets while I feel sure my DH param is "only" 2048 bits.
    – Law29
    Commented Nov 21, 2016 at 11:59
  • 1
    @Law29 This more looks like an ECDHE ServerKeyExchange. If using an elliptic curve, then the "03" means "this is a named curve, the next two bytes encode the curve identifier". Then "00 17" is the curve identifier, which is NIST P-256 (the most used curve for ECDHE). Then "41" is the public point length, which is exactly the right value for a P-256 point in uncompressed format; such a point would begin with a byte of value 0x04, and that's precisely what you have. To sum up: it seems your TLS 1.2 handshake really uses ECDHE, not DHE. Commented Nov 21, 2016 at 13:59

If you have the certificate in PEM format, you can try this command, it should give you a proper output from Openssl command.

openssl dhparam -inform PEM -in ./imapd.pem -check -text

(Sample output)
    PKCS#3 DH Parameters: (512 bit)
        generator: 2 (0x2)
DH parameters appear to be ok.

Hope this is what you are looking for.

  • The PEM format is default so you don't need flag -inform PEM. You usually also want -noout at the end to avoid repeating full file contents while checking these files. Commented Apr 14, 2022 at 14:35

David Loh's answer didn't work for me. It requires DH PARAMETERS and I have no idea where to get those from.

Thomas Pornin's answer was helpful, but I had to force TLS 1.2 to see the ServerKeyExchange (e.g. openssl s_client -connect example.org:443 -msg -tls1_2) and even then I wasn't super confident I was correctly interpreting the output.

I found another tool which worked better for my needs: sslyze

To install it:

pip install sslyze

Sample output:

$ python -m sslyze example.org | grep -iw dh
        TLS_DHE_RSA_WITH_AES_256_GCM_SHA384               256       DH (1024 bits) 
        TLS_DHE_RSA_WITH_AES_256_CBC_SHA256               256       DH (1024 bits) 
        TLS_DHE_RSA_WITH_AES_128_GCM_SHA256               128       DH (1024 bits) 
        TLS_DHE_RSA_WITH_AES_128_CBC_SHA256               128       DH (1024 bits) 
        * dh_param_size: DH parameter size is 1024, should be superior or equal to 2048.
  • The best answer for this question. Save my day, Thanks!
    – Jeff
    Commented Oct 26, 2023 at 3:42

You must log in to answer this question.