16

I am new to Python Requests and am encountering an IOError:[Errno 22] Invalid argument when I attempt a requests.get(). In short, I am attempting to connect to an internal web application using SSL and so I pass a cert/key combination per the Requests documentation.

I've spent quite a bit of time researching potential issues and saw some mention of potential SNI issues but am not savvy enough to know how I might go about remedying the issue (again, new to Requests). Appreciate any nudge in the right direction/where to dig in further (I'm guessing the urllib3 piece?)

My Code

import requests

cert_file_path = "/Users/me/Documents/cert.pem"
key_file_path = "/Users/me/Documents/key.pem"

url = "https://mydomain/path/to/something"
cert = (cert_file_path, key_file_path)
r = requests.get(url, cert=cert) 

My Error

IOError                               Traceback (most recent call last)
    <ipython-input-48-1ee4a7f23d00> in <module>()
          4 url = "https://mydomain/path/to/something"
          5 cert = (cert_file_path, key_file_path)
    ----> 6 r = requests.get(url, cert=cert)

    /Users/me/anaconda/lib/python2.7/site-packages/requests/api.pyc in get(url, **kwargs)
         66 
         67     kwargs.setdefault('allow_redirects', True)
    ---> 68     return request('get', url, **kwargs)
         69 
         70 

    /Users/me/anaconda/lib/python2.7/site-packages/requests/api.pyc in request(method, url, **kwargs)
         48 
         49     session = sessions.Session()
    ---> 50     response = session.request(method=method, url=url, **kwargs)
         51     # By explicitly closing the session, we avoid leaving sockets open which
         52     # can trigger a ResourceWarning in some cases, and look like a memory leak

    /Users/me/anaconda/lib/python2.7/site-packages/requests/sessions.pyc in request(self, method, url, params, data, headers, cookies, files, auth, timeout, allow_redirects, proxies, hooks, stream, verify, cert, json)
        462         }
        463         send_kwargs.update(settings)
    --> 464         resp = self.send(prep, **send_kwargs)
        465 
        466         return resp

    /Users/me/anaconda/lib/python2.7/site-packages/requests/sessions.pyc in send(self, request, **kwargs)
        574 
        575         # Send the request
    --> 576         r = adapter.send(request, **kwargs)
        577 
        578         # Total elapsed time of the request (approximately)

    /Users/me/anaconda/lib/python2.7/site-packages/requests/adapters.pyc in send(self, request, stream, timeout, verify, cert, proxies)
        368                     decode_content=False,
        369                     retries=self.max_retries,
    --> 370                     timeout=timeout
        371                 )
        372 

    /Users/me/anaconda/lib/python2.7/site-packages/requests/packages/urllib3/connectionpool.pyc in urlopen(self, method, url, body, headers, retries, redirect, assert_same_host, timeout, pool_timeout, release_conn, **response_kw)
        542             httplib_response = self._make_request(conn, method, url,
        543                                                   timeout=timeout_obj,
    --> 544                                                   body=body, headers=headers)
        545 
        546             # If we're going to release the connection in ``finally:``, then

    /Users/me/anaconda/lib/python2.7/site-packages/requests/packages/urllib3/connectionpool.pyc in _make_request(self, conn, method, url, timeout, **httplib_request_kw)
        339         # Trigger any extra validation we need to do.
        340         try:
    --> 341             self._validate_conn(conn)
        342         except (SocketTimeout, BaseSSLError) as e:
        343             # Py2 raises this as a BaseSSLError, Py3 raises it as socket timeout.

    /Users/me/anaconda/lib/python2.7/site-packages/requests/packages/urllib3/connectionpool.pyc in _validate_conn(self, conn)
        760         # Force connect early to allow us to validate the connection.
        761         if not getattr(conn, 'sock', None):  # AppEngine might not have  `.sock`
    --> 762             conn.connect()
        763 
        764         if not conn.is_verified:

    /Users/me/anaconda/lib/python2.7/site-packages/requests/packages/urllib3/connection.pyc in connect(self)
        236                                     ca_certs=self.ca_certs,
        237                                     server_hostname=hostname,
    --> 238                                     ssl_version=resolved_ssl_version)
        239 
        240         if self.assert_fingerprint:

    /Users/me/anaconda/lib/python2.7/site-packages/requests/packages/urllib3/util/ssl_.pyc in ssl_wrap_socket(sock, keyfile, certfile, cert_reqs, ca_certs, server_hostname, ssl_version, ciphers, ssl_context)
        261             raise
        262     if certfile:
    --> 263         context.load_cert_chain(certfile, keyfile)
        264     if HAS_SNI:  # Platform-specific: OpenSSL with enabled SNI
        265         return context.wrap_socket(sock, server_hostname=server_hostname)

    IOError: [Errno 22] Invalid argument

Environment

Python: Python 2.7.11 :: Anaconda 2.4.1 (x86_64)
Requests: 2.6.0
Mac OSX: Yosemite (10.10.5)

nacc
  • 311
  • 3
  • 8
  • 5
    Are you **sure** the cert and key file paths are correct, and have appropriate permission to be read by the program? – John Gordon Feb 17 '16 at 20:27
  • 1
    @JohnGordon the paths are definitely correct (I got something along the lines of "invalid path" in an earlier version when I had a typo). In terms of whether the cert/key can be read I'm game to check via a different methodology to validate if there's one I can use. In previous iterations it would throw something akin to 'cert/key mismatch' or 'invalid ssl' before I got which cert/key files I needed squared awa – nacc Feb 17 '16 at 20:37
  • 1
    Are you running this program directly as yourself, or is it being executed within some other context (such as within a web server)? If the latter, make sure that the files are readable in that context. – John Gordon Feb 17 '16 at 20:43
  • 2
    As a simple check, you could make a very short script that just tries to open both files, and see if it gets the same error. – John Gordon Feb 17 '16 at 20:44
  • @JohnGordon running it as myself (on same box I hit the browser with w/ no issues); both files open ok from bash/terminal – nacc Feb 17 '16 at 20:47
  • check [a related question](https://stackoverflow.com/questions/16903528/how-to-get-response-ssl-certificate-from-requests-in-python) there cert is a list not a tuple. – Alexander Brockmeier Apr 12 '21 at 21:07
  • similair to @JohnGordon , or , if that you are supplementing wrong format / content, ( even file extension not always indicate what's inside , make sure you had cert in cert.pem – Jack Wu Jun 01 '21 at 13:26
  • 1
    I'll expand on @JohnGordon's question. If you do `open("/Users/me/Documents/cert.pem")` in the file you are trying to run, does that work? – Bertik23 Sep 02 '21 at 14:41

2 Answers2

1

One thing to check: The client certificate file must include all of the certificates in the certificate chain, up to and including the certificate of root CA that signed the client's certificate.

Sam
  • 101
  • 1
  • 5
0

I may not be correct, but, are you sure the Python version you are using supports the arguments given in requests.get(*arguments)? Maybe update the Python version to like 3.7 and above

  • This does not provide an answer to the question. Once you have sufficient [reputation](https://stackoverflow.com/help/whats-reputation) you will be able to [comment on any post](https://stackoverflow.com/help/privileges/comment); instead, [provide answers that don't require clarification from the asker](https://meta.stackexchange.com/questions/214173/why-do-i-need-50-reputation-to-comment-what-can-i-do-instead). - [From Review](/review/late-answers/31312589) – gremur Mar 21 '22 at 13:39