#963 ssl handshake error: no shared cipher for prime256v1 ECDSA certificate

Reporter Kevin Locke
Owner Zash
Stars ★★ (2)  
  • Priority-Medium
  • Status-Fixed
  • Type-Defect
  • Milestone-0.10
  1. Kevin Locke on

    What steps will reproduce the problem? # Generate an ECDSA certificate which uses prime256v1 openssl ecparam -name prime256v1 -genkey -out "certs/localhost-ecc.key" openssl req -batch -config "certs/localhost.cnf" -key "certs/localhost-ecc.key" -nodes -x509 -out "certs/localhost-ecc.crt" # Run prosody with the certificate cat > prosody.cfg.lua <<PROSODY_CFG modules_enabled = { "tls"; } ssl = { key = "certs/localhost-ecc.key"; certificate = "certs/localhost-ecc.crt"; } VirtualHost "localhost" PROSODY_CFG ./prosody # Demonstrate connection failure openssl s_client -starttls xmpp -connect localhost:5222 </dev/null What is the expected output? A successful TLS connection is expected. The server would print "Client connected". The client would print the certificate contents then "DONE". What do you see instead? The TLS connection fails. The server will print "Client disconnected: ssl handshake error: no shared cipher". The client will print "140448209548544:error:14094410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure:../ssl/record/rec_layer_s3.c:1399:SSL alert number 40". What version of the product are you using? On what operating system? I have reproduced the issue using Prosody 0.9.12-2 on Debian 9 (stretch) and building from the current hg tip (8185:e89320b8a789) with LuaSec 0.6-3 and OpenSSL 1.1.0f-3. Please provide any additional information below. The issue appears to be caused by setting curve secp384r1 by default (at core/certmanager.lua:105) which causes an empty cipher list due to how ECDHE and ECDSA interact in OpenSSL 1.1.0. See https://github.com/openssl/openssl/issues/2033#issuecomment-265165765 Configuring curve prime256v1 explicitly works, but would fail with a secp384r1 ECDSA certificate. Removing the default curve in the code fixes the problem in a way that should work for all ECDSA certificates (and the s_client connection uses X25519 on my system). Is there a reason to set curve secp384r1 by default? Thanks, Kevin Related: https://prosody.im/issues/issue/879 https://prosody.im/issues/issue/943 https://prosody.im/issues/issue/951

  2. Zash on

    Hi, thanks for the report. So, even more fallout from this :( The reason we set a curve by default is because that was how you enabled ECDHE, but the meaning of that option has changed in LuaSec and/or OpenSSL in an incompatible way, without any way to detect the change.

  3. Kevin Locke on

    Hi Zash, You're right! After a bit of digging, it looks like OpenSSL < 1.0.2 requires calling SSL_CTX_set_tmp_ecdh to enable ECDH. 1.0.2 <= OpenSSL < 1.1.0 can use SSL_CTX_set_ecdh_auto to enable ECDH without limiting the curves.[1] OpenSSL >= 1.1.0 removed SSL_CTX_set_ecdh_auto and enables ECDH by default.[2] LuaSec 0.6 setcurve calls SSL_CTX_set_tmp_ecdh. LuaSec master setcurve calls SSL_CTX_set1_curves_list and SSL_CTX_set_ecdh_auto where present.[3] Perhaps the best solution for Prosody would be to not set a default curve on OpenSSL 1.1.0 and later. Unfortunately, it doesn't look like LuaSec exposes the OpenSSL version information. I could submit an issue to LuaSec about that. Thoughts? 1. https://bugs.python.org/issue29697 2. https://github.com/openssl/openssl/commit/fe6ef2472db933f01b59cad82aa925736935984b 3. https://github.com/brunoos/luasec/commit/231563682a721a39b047db5f415363a88bf3c872

  4. Zash on

    A bunch of existing discussion can be found in https://github.com/brunoos/luasec/pull/47 FWIW

  5. Zash on

    This was fixed in https://hg.prosody.im/trunk/rev/92cddfe65003 according to bisect

    • tags Milestone-0.10 Status-Fixed
    • owner Zash

New comment