22

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?

Yuri
  • 115
  • 3

3 Answers3

18

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).

Thomas Pornin
  • 568
  • 3
  • 11
  • 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: http://httpd.apache.org/docs/trunk/mod/mod_ssl.html#sslcertificatefile (which notes the issue about Java clients). – dave_thompson_085 Apr 24 '15 at 09: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 Jun 09 '15 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. – Thomas Pornin Jun 09 '15 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 Nov 21 '16 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. – Thomas Pornin Nov 21 '16 at 13:59
  • @ThomasPornin you are (of course) correct, this conversation selected an ECDHE cipher. Thank you! – Law29 Nov 22 '16 at 10:18
  • This was useful, but peeking at hexdumps could be improved; is there an `s_client` option to have it fully decode the SSL traffic (decode as in explain the protocol messages, like the ASN.1 decoder)? – mirabilos May 10 '23 at 21:04
15

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)
        prime:
            xx:xx:xx:xx
            xx:xx:xx:xx
            xx:xx:xx:xx
        generator: 2 (0x2)
DH parameters appear to be ok.
-----BEGIN DH PARAMETERS-----
XXXX
XXXX
-----END DH PARAMETERS-----

Hope this is what you are looking for.

David Loh
  • 159
  • 1
  • 4
  • 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. – Mikko Rantalainen Apr 14 '22 at 14:35
0

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.
bmaupin
  • 313
  • 3
  • 11