The other day, we had a Scrapy user report an issue connecting to https://www.skelbiu.lt/ with OpenSSL 1.1 [1]

To not mix scrapy's things with Twisted Web, I used this (adapted from official docs):

from __future__ import print_function

from twisted.internet import reactor
from twisted.web.client import Agent
from twisted.web.http_headers import Headers

agent = Agent(reactor)

d = agent.request(
    Headers({'User-Agent': ['Twisted Web Client Example']}),

def cbResponse(ignored):
    print('Response received')

def cbShutdown(ignored):


And I did get a Handshake failure too:

    $ python twistedtest.py
    [Failure instance: Traceback (failure with no frames): <class 'twisted.web._newclient.ResponseNeverReceived'>: [<twisted.python.failure.Failure OpenSSL.SSL.Error: [('SSL routines', 'ssl3_read_bytes', 'sslv3 alert handshake failure')]>]

It seems this happens (at least) with OpenSSL 1.1.0e (currently in Debian 9 sid [2])
It does not happen (for me) with OpenSSL 1.0.2g for example.

I dug into this this afternoon and narrowed it down to the use of 
_defaultCurveName = u"prime256v1"
in twisted.internet._sslverify.py

I tried patching the current trunk with _defaultCurveName = u"secp384r1" (the EC that ssllabs.com reports)
and it did work.

Looking at ClientHello messages for openssl 1.0.2 and 1.1 [4]:
with 1.1, only 1 Elliptic Curve is sent by Twisted Web Agent, secp256r1

openssl v1.1 client uses 4 by default: ecdh_x25519, secp256r1, secp521r1, secp384r1

I was wondering what is the proper way to configure requested Elliptic Curves.
I haven't seen any interface for this, contrary to ciphers with acceptableCiphers.

Thank you for your input.


[1] https://github.com/scrapy/scrapy/issues/2717
[2] https://packages.debian.org/fr/source/sid/openssl
[3] https://github.com/twisted/twisted/blob/78679af87e349721a167f35bef239e192e91d126/src/twisted/internet/_sslverify.py#L1904
[4] https://github.com/scrapy/scrapy/issues/2717#issuecomment-297464034