How to generate new, 2048-bit Diffie-Hellman parameters with Java keytool?
We are non-experts trying - unsuccessfully so far - to update our web server (JBoss-5.1.0.GA) settings to meet Diffie-Hellman standards. After running a test on https://weakdh.org/sysadmin.html, we are told that we need to "generate new, 2048-bit Diffie-Hellman parameters". In the past, we have generated keys with Java keytool, but we have been unable to find any information on generating a new, 2048-bit Diffie-Hellman parameter with Java keytool. Does anyone know how to do this or could point us in the right direction? Thank you!
You can't do that with keytool. First, keytool
doesn't support DH at all. Second, keytool
doesn't generate parameters by themselves for any algorithm, only a privatekey/keypair. Third, when keytool
generates a keypair it also generates a self-signed cert (which sometimes is subsequently replaced by a "real" CA-issued cert) and it's impossible to generate a self-signed cert for DH because DH doesn't sign. You could write a very simple (about 10 lines) Java program to generate DH parameters. But it probably wouldn't do you any good because:
Java doesn't accept DHE parameters here anyway. JbossWS (the Jboss webserver, later Wildfly) is a fork of Tomcat, and normally uses the Java implementation of SSL/TLS, JSSE. Up through Java 7, JSSE uses its own DHE parameters which are 768-bit which is unacceptably weak. (Except for the EXPORT suites where JSSE obeys the RFC requirement for DH-512, which is totally broken, but then the EXPORT suites are by design totally broken anyway, and disabled by default in Java 7 up.) Java 8 JSSE allows you to control the size of the DHE parameters, but not the actual value.
Your (some overlapping) options are:
Use Java 8. JSSE in Java 8, but not earlier, defaults DHE to 1024 bits, which most authorities consider strong enough even though weakdh.org does not, and allows you to specify more, see https://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html#customizing_dh_keys and for background https://stackoverflow.com/questions/30352105/how-to-set-custom-dh-group-in-java-sslengine-to-prevent-logjam-attack . Note that if you have any Java clients before Java 8, they will fail if the server uses DHE over 1024 bits. I don't know any other clients that have this problem, but test yours before committing to this change.
Enable ECDHE. JSSE in Java 7 and later implements ECDHE, which is not subject to precomputation like DHE, (normally) using P-256, which is more than strong enough. (Although some people don't trust any of the NIST ECC curves because NIST in general is influenced by NSA, although no open source I know of has shown a problem in the ECC curves specifically.) Java 6 actually has the JSSE part for ECDHE but it is only enabled if the JVM has a crypto "provider" for ECC primitives, which Java 6 doesn't. bcprov-*-jdk15on from http://www.bouncycastle.org/ is a JCE provider for a range of Java crypto primitives including ECC, so if you add the jar to your JRE/lib/ext
and add org.bouncycastle.jce.provider.BouncyCastleProvider
to the list in JRE/lib/security/java.security
(or do a suitable Security.add/insertProvider()
somewhere early in your code) Java 6 can do ECDHE. Of course whether you should have any Java 6 still in use is a question on its own.
A few years ago, support for ECDHE in browsers and other clients was iffy, but today AFAIK all up-to-date browsers support it and prefer it to DHE -- that is, the browser hello lists the ECDHE suites before the DHE suites so that if the server implements both it should choose ECDHE. Non-browser clients maybe not; test to be certain.
Disable DHE. You can configure the list of ciphers in the Connector attribute to exclude DHE ciphers; while you're at it also exclude staticDH and staticECDH which are useless, and (single) DES and (all) "EXPORT" if present (Java 6). This means browsers and clients that don't do ECHDE will be stuck with plain-RSA and no Forward Secrecy, but at least they have "current" secrecy. I don't recall for sure, but I think 5.1 Connector config was still someplace like $server/deploy/jbossweb/server.xml
.
Try native. Tomcat, which as I said JbossWS started from, has an option to implement HTTPS (SSL/TLS) using "native" aka "APR" which is actually OpenSSL inside rather than JSSE. I have had mixed success in getting this option to work on JbossWS, and don't recall about 5.1. If your JbossWS has a workable TC-native option, and if it can handle configuring DH parameters, then use openssl to generate the DH parameters and the JbossWS-native instructions to configure them.
Actually you can specify custom DHE Parameters with recent Java 8 versions. That is independend of the application (as Long as it using JSSE TLS implementation).
You first need to specify the size of the DHE key to use (-Djdk.tls.ephemeralDHKeySize=1024
or -Djdk.tls.ephemeralDHKeySize=2048
). On the Server this will use a pre-defined generator/prime combination for DHE. With Java 8 only 1024 or 2048 can be used, JDK 9 will support larger sizes.
If you want to provide a different combination you can specify them in jre/lib/security/Java.security with the jdk.tls.server.defaultDHEParameters
security property (since 8u51). It takes a list of Parameters (one for each used keysize) and it must contain the prime and the Generator (typically 2 or 5) as hex.
If you used openssl dhparam -out dhparam2048.pem 2048
to generate a new pair you can use openssl dhparam -noout -text -check -in dhparam2048.pem
to read and print that file in text mode. You will have to copy and paste the text into the Java security properties (using tr -d ':'
to remove the :
between the openssl hex representation)
Here is a sample (1024 bis only):
>openssl dhparam -in p -check -text -noout | tr -d ':'
PKCS#3 DH Parameters: (1024 bit)
prime:
00f7a63b59edcc43a43df12077f0e9
14129c20a73cef95f919896e608ebc
8722776c948765bbbf61542e118329
6c6ea74ecbded3a93aff77a062aba4
fcf04fc01030e65077f5a802605058
65b836368dd5ea389d77691fac0f2c
f7a161c51c8e97ddecb3cf7f872b0c
cfaf54373d5203edcabc575e871bb1
107ec2f30c78ebf403
generator: 2 (0x2)
DH parameters appear to be ok.
And this results in
jdk.tls.server.defaultDHEParameters= \
{ \
00f7a63b59edcc43a43df12077f0e9 \
14129c20a73cef95f919896e608ebc \
8722776c948765bbbf61542e118329 \
6c6ea74ecbded3a93aff77a062aba4 \
fcf04fc01030e65077f5a802605058 \
65b836368dd5ea389d77691fac0f2c \
f7a161c51c8e97ddecb3cf7f872b0c \
cfaf54373d5203edcabc575e871bb1 \
107ec2f30c78ebf403, 2 }
You should restart the Server and verify that it actually uses this prime (and not the default ones) as the process is not straight Forward, so a lot can go wrong. The Default is defined in source, for 2048 bit the prime is from TLS FFDHE draft.
For example when running openssl s_client, I can see the 1024bit prime (ffffff ffffffffffc90f...5381ffffffffffffffff) when connecting to an Java 8 JSSE Server:
>openssl s_client -msg -cipher DHE-RSA-AES128-SHA256 -connect localhost:1234
...
<<< TLS 1.2 Handshake [length 018f], ServerKeyExchange
0c 00 01 8b 00 80 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
08 79 8e 34 04 dd ef 95 19 b3 cd 3a 43 1b 30 2b
0a 6d f2 5f 14 37 4f e1 35 6d 6d 51 c2 45 e4 85
b5 76 62 5e 7e c6 f4 4c 42 e9 a6 37 ed 6b 0b ff
5c b6 f4 06 b7 ed ee 38 6b fb 5a 89 9f a5 ae 9f
24 11 7c 4b 1f e6 49 28 66 51 ec e6 53 81 ff ff
ff ff ff ff ff ff 00 01 02 ...
Instead of this, you must see your custom Parameters when installed.
The Default Parameters for Java 7 (768bit) would be "e9e642...7a3daf" wit a long generator "30470ad..529252" as defined in the ParameterCache.
I've been going through this same problem, but from Glassfish.
Firstly, I'd recommend (if you can) to put some sort of reverse proxy in front of your JBoss server as it will remove the link between the cipher/certificate security and the version of Java you are running.
To get a larger Ephemeral DH key length than 768 bits you need to be running on Java 8. 1024 is the new default, and you can go up to 2048 using the jdk.tls.ephemeralDHKeySize
(details: customising DH keys). From what I could find, there is no concept of regenerating the key parameters separately in Java.