I'm working on a simple python script that uses a base64 encoded certificate and private key. These are base64 encoded string literals in the script.
I create a Pkcs12Context class definition like so (where it loads the cert and the key).
class Pkcs12Context(requests.packages.urllib3.contrib.pyopenssl.OpenSSL.SSL.Context):
def __init__(self, method):
super(Pkcs12Context, self).__init__(method)
self.use_certificate(load_certificate(FILETYPE_PEM, base64.b64decode(ENCODED_CERT)))
self.use_privatekey(load_privatekey(FILETYPE_PEM, base64.b64decode(ENCODED_PRIVATEKEY)))
Later on I take a json payload object and sign it using jwt.encode()
, providing it the decoded privatekey.
Then I make a requests request like so:
response = requests.post('https://<sampleapiendpoint>', headers={"Content-Type": "text/xml"}, data=signed_payload, timeout=60)
The problem is when I run the script with python2, it will error out:
Traceback (most recent call last):
File "apirequest.py", line 171, in <module>
response = requests.post('https://<sampleapiendpoint>', headers={"Content-Type": "text/xml"}, data=signed_payload, timeout=60)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/requests/api.py", line 108, in post
return request('post', url, data=data, json=json, **kwargs)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/requests/api.py", line 50, in request
response = session.request(method=method, url=url, **kwargs)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/requests/sessions.py", line 464, in request
resp = self.send(prep, **send_kwargs)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/requests/sessions.py", line 576, in send
r = adapter.send(request, **kwargs)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/requests/adapters.py", line 431, in send
raise SSLError(e, request=request)
requests.exceptions.SSLError: [SSL: SSLV3_ALERT_HANDSHAKE_FAILURE] sslv3 alert handshake failure (_ssl.c:727)
If I use python3 I get the following callstack:
Traceback (most recent call last):
File "/Users/<username>/Projects/<folder>/<folder2>/apicall.py", line 94, in <module>
class Pkcs12Context(requests.packages.urllib3.contrib.pyopenssl.OpenSSL.SSL.Context):
AttributeError: module 'requests.packages.urllib3.contrib' has no attribute 'pyopenssl'
I have tried uninstalling and reinstalling pyopenssl to no avail. I have tried both python2 and python3, neither work. I do suspect however that the python2 one is working, but there's something wrong with the certs/keys so that the handshake never succeeds (which means its a script or endpoint configuration problem). I have also tried a potential solution described on a forum at https://github.com/certbot/certbot/issues/6328, where they say to try to use requests 2.6.0, which I am. Is the python2 version actually working, but there's a cert/key configuration problem with the api endpoint? And why doesn't the python3 version work?
Here is the output of the pip freeze command:
certifi==2021.10.8
cffi==1.15.0
charset-normalizer==2.0.12
cryptography==36.0.1
idna==3.3
pycparser==2.21
PyJWT==2.3.0
pyOpenSSL==22.0.0
requests==2.6.0
urllib3==1.26.8
I could not solve this issue directly. Instead it was solved with the following approach. Instead of creating a Pkcs12Context, we just don't do that at all, and use the certs argument of the requests.posts method to provide the certs to the request call.
response = requests.post('https://<url>',
cert=(SSL_CERTIFICATE_FILENAME, SSL_CERTIFICATE_PVKEY_FILENAME),
headers={"Content-Type": "text/xml"}, data=encoded, timeout=60)