When using SSL, no Diffie-Hellman
are being loaded even though they are available.
openssl ciphers -V 'ALL' | grep -i TLSv1.2 | grep DHE | grep Kx=DH
0x00,0xA3 - DHE-DSS-AES256-GCM-SHA384 TLSv1.2 Kx=DH Au=DSS Enc=AESGCM(256) Mac=AEAD
0x00,0x9F - DHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=DH Au=RSA Enc=AESGCM(256) Mac=AEAD
0x00,0x6B - DHE-RSA-AES256-SHA256 TLSv1.2 Kx=DH Au=RSA Enc=AES(256) Mac=SHA256
0x00,0x6A - DHE-DSS-AES256-SHA256 TLSv1.2 Kx=DH Au=DSS Enc=AES(256) Mac=SHA256
0x00,0xA2 - DHE-DSS-AES128-GCM-SHA256 TLSv1.2 Kx=DH Au=DSS Enc=AESGCM(128) Mac=AEAD
0x00,0x9E - DHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=DH Au=RSA Enc=AESGCM(128) Mac=AEAD
0x00,0x67 - DHE-RSA-AES128-SHA256 TLSv1.2 Kx=DH Au=RSA Enc=AES(128) Mac=SHA256
0x00,0x40 - DHE-DSS-AES128-SHA256 TLSv1.2 Kx=DH Au=DSS Enc=AES(128) Mac=SHA256
Can you say more what you mean when you say they are not "being loaded"?
Well... lets say I load the ciphers
ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:DHE-RSA-AES256-SHA256
I only get.. when i check the loaded ciphers agaist gunicorn server listening on 443.
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (brainpoolP256r1) - A
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 (brainpoolP256r1) - A
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (brainpoolP256r1) - A
DHE's are also listed in the HIGH
constant of ciphers... and you will find that no DHE's load / are presented to the client as a cipher.
Are you connecting directly to Gunicorn? Or is there a PaaS you're deploying to?
Direct
The output you pasted looks like elliptic curve Diffie-Hellman is being offered (ECDHE):
| ssl-enum-ciphers:
| TLSv1.2:
| ciphers:
| TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (brainpoolP256r1) - A
| TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 (brainpoolP256r1) - A
| TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (brainpoolP256r1) - A
Is that the end of the ssl-enum-ciphers
output?
yup via nmap --script ssl-cert,ssl-enum-ciphers -p 443 <host>
or you can use https://www.ssllabs.com/ssltest/
@tilgovi I managed to make this work , but I had to rewrite workers/sync.py
and make the ssl.wrap_socket
a SSLContext.wrap_socket
, though this is test.. what I ended up doing was generating a dhparam via openssl and loading it via context.load_dh_params
def handle(self, listener, client, addr):
req = None
try:
if self.cfg.is_ssl:
context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
context.options |= ssl.OP_SINGLE_DH_USE
context.set_ciphers(self.cfg.ssl_options.get('ciphers'))
context.load_cert_chain(self.cfg.ssl_options.get('certfile'), keyfile=self.cfg.ssl_options.get('keyfile'))
context.load_verify_locations(cafile=self.cfg.ssl_options.get('ca_certs'))
context.load_dh_params('ssl_cert/dhparam.crt')
client = context.wrap_socket(client, server_side=True, do_handshake_on_connect=False)
... but its something to work off..
scan results now come back with
TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 (dh 2048) - A
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (brainpoolP256r1) - A
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 (brainpoolP256r1) - A
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (brainpoolP256r1) - A
Rather than create a dhparam (which you isnt required for nginx or apache) just generate a dynamic one on startup?
Reading futher into python ssl library, I don't think the auto generate will be possible... anyway may need to incorporate my changes with a dhparam-cert or something, so people can enable / use DH ciphers.
This is what I get now via the following ciphers with my patch
TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 (dh 2048)
TLS_DHE_RSA_WITH_AES_256_CBC_SHA (dh 2048)
TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 (dh 2048)
TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 (dh 2048)
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (brainpoolP256r1)
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (brainpoolP256r1)
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 (brainpoolP256r1)
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (brainpoolP256r1)
Via
--ciphers="EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH:DHE+RSA+AES"
We have #1140 and #1680 that could be related. If you can help in any way that would be very much appreciated.
@VeNoMouS I think you have already found the limitation, that load_dh_params()
must be called in-order for the DH ciphers to be considered in Python. At least I think that is the case. It is backed-up by this note in the issue when the cipher was made available:
In order to enable DH ciphers the SSL implementation the in the file Modules/_ssl.c, it must issue a DH_generate_parameters() if a cipher is DH.
Since that method is on the context, and ssl.wrap_socket
is deprecated (underneath it just delegates to SSLContext
, then your patch seems correct. Additional config options would be require to pass the DH params.
@javabrett yea you have to pass a dh cert in order to use it so it would be best handled by a opt parameter from cmd line, i simply hard coded mine as i needed to get it going for a client.
ie if dh cert parameter in getopt... then load_dh_params()
.... etc..
I will try find some time to do a proper push request.
Most helpful comment
@javabrett yea you have to pass a dh cert in order to use it so it would be best handled by a opt parameter from cmd line, i simply hard coded mine as i needed to get it going for a client.
ie if dh cert parameter in getopt... then
load_dh_params()
.... etc..I will try find some time to do a proper push request.