Requests module throwing OpenSSL.SSL.Error

I'm using a REST API from euronext.com, to go any further I need to verify the server certificate and send my own client certificate through the module requests.

I already did some testing with curl, both .crt/.pem files were accepted.

But requests is still throwing :

DEBUG:urllib3.connectionpool:Starting new HTTPS connection (1): saturn-api-h.euronext.com
Traceback (most recent call last):
  File "C:\python36\lib\site-packages\urllib3\contrib\pyopenssl.py", line 441, in wrap_socket
cnx.do_handshake()
  File "C:\python36\lib\site-packages\OpenSSL\SSL.py", line 1806, in do_handshake
self._raise_ssl_error(self._ssl, result)
  File "C:\python36\lib\site-packages\OpenSSL\SSL.py", line 1546, in _raise_ssl_error
_raise_current_error()
  File "C:\python36\lib\site-packages\OpenSSL\_util.py", line 54, in exception_from_error_queue
raise exception_type(errors)
OpenSSL.SSL.Error: [('SSL routines', 'tls_process_server_certificate', 'certificate verify failed')]

What I did try to solve the issue :

Working curl:

curl -i -vvv -X POST https://saturn-api-h.euronext.com/SaturnWebServices/rest/Authentication/AuthenticateUser -H "Content-Type: application/json" --cert ./client.crt --cacert ./digicert-full-chain.crt

With a valid Authorization headers it return a 200 status code, without it 401 "Access denied!". If the certificate validation fails, it redirects to euronext.com with status code 302.

Problematic python:

endpoint = 'https://saturn-api-h.euronext.com/SaturnWebServices/rest/Authentication/AuthenticateUser'       
headers = { 'Content-Type': 'application/json', } #'Authorization': 'Basic <auth_string>',

r = requests.post(endpoint, headers = headers, verify = './digicert-full-chain.crt', cert = './client.crt')

Certificates:

Why is curl command working whereas python's requests module is failling?

Is there any way to show the complete handshake process from the requests module?

Upvotes: 2

Views: 2582

Answers (1)

I solved the problem myself, a certificate was missing from the full chain.

Doing /usr/local/lib/python3.4/dist-packages/certifi/cacert.pem > certifi-digicert.pem; digicert-full-chain.pem >> certifi-digicert.pem and passing the resulting certificate to the verify argument worked.

As a side note, I used the strace command to compare certificate locations from both python and curl:

  • strace <python_command> |& grep open | grep -E 'crt|pem'
  • strace <curl_command> |& grep open | grep -E 'crt|pem'

I also checked with Wireshark to get the full handshake process, the pyOpenSSL module was getting an error after the server's Certificate Request. Alert (Level: Fatal, Description: Unknown CA).

Upvotes: 2

Related Questions