2

See updates

I'm trying to send request to a web server with a self-signed certificate (works fine on sites that aren't self-signed) and i keep getting the error:

SSLEOFERROR EOF occurred in violation of protocol 

Conversely when using requests, the non-async http client for python, setting ssl_verify to false allows for a successful connection to the server. However the async http client, asks, lacks such a feature, i get the SSLEOFERROR.

Asks does allow accepting a customized ssl.SSLContext object, but after several attempts at this, and even adding the self-signed cert to my local keystore, nothing has resulted in a successful connection and the error stays the same.

import asks
import trio
from asks.sessions import Session

url_list = ['facebook.com', 'https://example.com']
results=[]

ssl_context=ssl.SSLContext()
ssl_context.verify_mode=ssl.CERT_NONE
ssl_context.check_hostname = False


async def grabber(s,url):
    r=await s.get(path='/'+url)
    results.append(r)

async def main(url_list)
    s = Session(connections=2,ssl_context=ssl_context)
    s.base_location='https://self-signedcert-site/'
    s.endpoint='path/to/restapi'
    async with trio.open_nursery() as n:
            for url in url_list:
            n.start_soon(grabber, s, url)

trio.run(main,url_list)

Results in the below (handtyped traceback.. not able to share/paste from the erroring machine) Begin SSLEOFERROR Traceback:

Traceback (most recent call last):
line 463 in _retry 
   ret = fn(*args)
line 718 in read
   v= self._sslobj.read(len)
ssl.SSLEOFError: EOF occured in violation of protocol (_ssl.c:2508)

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
line 90, in runcode
    exec(code, self.locals)
File "<input>", line 28, in <module> run.py line 1783 in run
    raise runner.main_task_outcome.error
file"<input>", line 26 in main
file _run.py, line 725, in __aexit__ 
     raise combined error_from_nursery
file"<input>", line 15 in grabber
File "asks/sessions.py", line 253, in _handle_exception
     raise e
File ...asks\sessions.py" , line 186 in request
     sock,r = await req_obj.make_request()
file ...request_object.py ", line 217 in make_request
     response obj=await self._request_io(req, req_body, hconnection)
file ..request_object.py", line 254 in _request_io
     response_obj = await 
     self._catch_response(hcconection)
file ..request_object.py", line 596, in _catch_response
     data=await self._recv_event(hcconection)
file "...request_object.py", line 618, in _recv_event
     (await asynclib.recv(self.sock,10000)))
File "..._event_loop_wrappers.py", line 47 in trio_receive_some
     return await sock.receive_some(max_bytes)
file "..._ssl.py" line 657 in receive_some
     return await self._retry(self._ssl_object.read, max_bytes)
File"....trio\_ssl.py", line 468 in _retry
     raise trio.BrokenResourceerror from exc
     Trio.BrokenResourceError

UPDATE I've identified some things.

If instead of using a session object I just use asks.get() i'm able to see granular changes in responses:

Asks Library


SSLEOFERROR: [Error fixed by using pip to install asks -- conda-forge is running 3 releases behind]

asks.get('https://url', auth=BasicAuth(usr_pw))

Invalid HTTP Response Error:

asks.get('https:url/rest/api/path',auth=BasicAuth(usr_pw))

Body of page is returned as expected:

asks.get('https://google.com')

Requests Library


Body of page is returned as expected:

requests.get('https://url', auth=HTTPBasicAuth=(usr_pw),verify=false)

Proper response returned from API as expected:

requests.get('https:url/rest/api/path', auth=HTTPBasicAuth=(usr_pw))

Considering there is another type of error I'm able to generate (invalid http response) I've added some more traceback for that Begin Invalid HTTP Response Traceback:

[full paths redacted]

File "....\asks\sessions.py", line 185, in request
   sock, r = await req_obj.make_request()
file ....\asks\request_object.py", line 214, in make_request
   response_obj = await self._request_io(req, req_body, h11_connection)
file "...\asks\request_object.py", line 251, in _request_io
   response_obj = await self._catch_response(h11_connection)
file"...\asks\request_object.py", line 599, in _catch_response
   assert isinstance(endof, h11.EndOfMessage)
AssertionError

The above exception was the direct cause of the following exception
[some output redacted]
file "...\trio\_core\_run.py", in 1783, in run
    raise runner.main_task_outcome.error
file "...\my_script_thats_having_this_error, line 33, in main
   n.start_soon(grabber,s)
File"....\trio\_core\_run.py", line 725 in __aexit__ 
   raise combined_error_from_nursery
File "...\my_script_thats_having_this_error, line 30 in request
   r = await s.request(method, url=uri, **kwargs)
File "...\asks\sessions.py", line 215, in request
   await self._handle_exception(e,sock)
File "...\asks\sessions.py", line 253, in _handle_exception
    raise BadHttpResponse('invalid HTTP response from server. ') from e asks.errors.BadHttpResponse: Invalid HTTP response from server.
Info5ek
  • 1,227
  • 4
  • 17
  • 25

1 Answers1

3

I tried using asks v2.3.5 to connect to a site with a self-signed certificate, and it succeeded just fine:

>>> trio.run(asks.get, "https://self-signed.badssl.com")
<Response 200 OK>

This is a serious bug... it means asks actually has the equivalent of verify=False set by default. I expect asks will make an emergency release in the next few days to fix this. See: https://github.com/theelous3/asks/issues/134 [Edit: this was fixed in asks v2.3.6.]

But back to your question! Given that asks does verify=False by default, I don't think the self-signed cert is causing your problem. Anyway, a self-signed cert should cause a SSLCertVerificationError, not a SSLEOFError.

Unfortunately, I don't think there's enough information here to figure out what your actual problem is :-(. The SSLEOFError exception means that the server is abruptly closing their connection. Maybe something's going wrong in the handshake? Maybe asks and requests are configured to offer a different set of cipher suites, and the server doesn't like asks's offering? These are wild guesses though :-/. I'd probably try wireshark next to find out what's actually happening.

Nathaniel J. Smith
  • 11,613
  • 4
  • 41
  • 49
  • I've used wireshark and it looks like the handshake is completed. There is application layer data that's transmitted. But it's encrypted so I can't tell what's happening. I tried to run a proxy to intercept and show the unencrypted traffic but I could not successfully get asks to use my proxy. Do you have any alternatives to trio+asks.. i have spent 36+ hours trying to debug this to no avail and believe myself to be at wits end. – Info5ek Sep 01 '19 at 08:53
  • 1
    Have you tried upgrading to the latest version of asks? I just noticed that your traceback there has a reference to `event_loop_wrappers`, which I think hasn't been used anytime in the last 3 releases... – Nathaniel J. Smith Sep 01 '19 at 09:48
  • i got it from the conda forge -- anaconda.org/conda-forge/asks which has version 2.2.1. Pip has version 2.3.5... :\ I will try to reinstall with pip to get the later version from pypi.org – Info5ek Sep 01 '19 at 09:52
  • I got latest version installed with pip. It didn't seem to fix the issue. However I've updated the original post with some interesting findings. – Info5ek Sep 01 '19 at 19:16
  • Seems some things in my environment were stale, the SSLEOFERROR issue isn't occurring now after the update. Thanks. – Info5ek Sep 02 '19 at 01:07