Skip to content
Advertisement

PEM Certificate & TLS Verification against REST api

I have been provided with a pem certificate to authenticate with a third party. Authenticating using certificates is a new concept for me.

Inside are two certificates and a private key.

The issuer has advised they do not support SSL verification but use TLS(1.1/1.2).

I have run a script as below:

import requests as req
import json

url = 'https://url.com/call'
certificate_file = "C:/certs/cert.pem"

headers = {"Content-Type": "application/json"}
 
req_body ={
    "network":{
                "network_id": 12345
    },
    "branch":{
                "branch_id": 12345,
    },
  "export_period":{
        "start_date_time": "16-11-2021 00:00:00",
        "end_date_time": "17-11-2021 00:00:00"
    }
}
 
jsonObject = json.dumps(req_body)
response = req.post(url,headers=headers,params=jsonObject,verify=certificate_file)

I’m getting the following error:

SSLError: HTTPSConnectionPool(host=’url.com, port=443): Max retries exceeded with url: /call?%7B%22network%22:%20%7B%22network_id%22:%2012345%7D,%20%22branch%22:%20%7B%22branch_id%22:%2012345%7D,%20%22export_period%22:%20%7B%22start_date_time%22:%20%2216-11-2021%2000:00:00%22,%20%22end_date_time%22:%20%2217-11-2021%2000:00:00%22%7D%7D (Caused by SSLError(SSLCertVerificationError(1, ‘[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1123)’)))

Would appreciate guidance, my gut says I should be doing something specific for TLS hence the SSL error.

Advertisement

Answer

The issuer is using an up to date version of HTTPS – SSL is the commonly used term but TLS is the more correct one. Sounds like their setup is correct – meaning you need to call it with a trusted client certificate, as part of an HTTPS request.

I would recommend doing it with the curl tool first so that you can verify that the API works as expected.

curl -s -X GET "https://api.example.com/test" 
--cert ./certs/example.client.pem 
--key ./certs/example.client.key 
--cacert ./certs/ca.pem 
-H "Content-Type: application/json"

Split the certs into separate files as above. Sounds like one of them is a root certificate authority that you need to tell the client tech stack to trust – for curl this is done using the cacert parameter as above.

Once this is working you can follow the same approach in the Python requests library. I believe this uses cert and verify parameters like this. So it looks like your code is not far off.

result = requests.get(
    'https://api.example.com',
    cert=('example.pem', 'example.key'),
    verify='ca.pem')

MORE ABOUT MUTUAL TLS

Out of interest, if you ever want to demystify Mutual TLS and understand more, have a look at these advanced Curity resources:

These include an OpenSSL Script you can run, to see what the separated certificate files should look like.

User contributions licensed under: CC BY-SA
6 People found this is helpful
Advertisement