0

When trying to call an API using python Requests I'm getting certificate verify failed: unable to get local issuer certificate error.

I have added the SSL certificate in cacert.pem of certifi. This did not fix the problem.

data = {'foo':'bar'} url = 'hostname' r = requests.post(url, data=data) print(r) 

The above code only works when I put verify=False in the above code.

I have also extracted SSL certificate of API using the below code and added it to certifi cacert.pem but that too did not work.

import ssl, socket myhostname = 'hostname' myctx = ssl.create_default_context() myctx.check_hostname = False myctx.verify_mode = ssl.CERT_NONE s = myctx.wrap_socket(socket.socket(), server_hostname=myhostname) s.connect((myhostname, 443)) bcert = s.getpeercert(binary_form=True) cert = ssl.DER_cert_to_PEM_cert(bcert) 

Below is the error that is getting thrown

Traceback (most recent call last): File "C:\Users\user\AppData\Local\Programs\Python\Python38-32\lib\site-packages\urllib3\connectionpool.py", line 670, in urlopen httplib_response = self._make_request( File "C:\Users\user\AppData\Local\Programs\Python\Python38-32\lib\site-packages\urllib3\connectionpool.py", line 381, in _make_request self._validate_conn(conn) File "C:\Users\user\AppData\Local\Programs\Python\Python38-32\lib\site-packages\urllib3\connectionpool.py", line 976, in _validate_conn conn.connect() File "C:\Users\user\AppData\Local\Programs\Python\Python38-32\lib\site-packages\urllib3\connection.py", line 361, in connect self.sock = ssl_wrap_socket( File "C:\Users\user\AppData\Local\Programs\Python\Python38-32\lib\site-packages\urllib3\util\ssl_.py", line 377, in ssl_wrap_socket return context.wrap_socket(sock, server_hostname=server_hostname) File "C:\Users\user\AppData\Local\Programs\Python\Python38-32\lib\ssl.py", line 500, in wrap_socket return self.sslsocket_class._create( File "C:\Users\user\AppData\Local\Programs\Python\Python38-32\lib\ssl.py", line 1040, in _create self.do_handshake() File "C:\Users\user\AppData\Local\Programs\Python\Python38-32\lib\ssl.py", line 1309, in do_handshake self._sslobj.do_handshake() ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1108) 
3
  • Have you tried setting REQUESTS_CA_BUNDLE to point to your certs? I’ve had issues before where I’ve had to explicitly set that value and that fixed cert issues (the default certs with python did not work with the self-signed certificates on the sites I needed to hit). Commented Apr 30, 2020 at 4:57
  • Yes, I have set REQUESTS_CA_BUNDLE to my cert. This did not solve the issue. Commented Apr 30, 2020 at 5:04
  • It does not help to add a normal leaf certificate to cacert.pem since it is not a CA cert. It is unclear if this is the case here or not since nothing is known about the target and its certificate and what initially caused the problem. Commented Apr 30, 2020 at 5:25

2 Answers 2

1

I have also extracted SSL certificate of API

My guess is that you used leaf server certificate as CA, and that's not how cert validation works. The SSL library on your side is trying to build a trust chain. Typical server certificate chain looks like this:

(CA ->) Intermediate CA -> server certificate

The CA cert is not sent in the TLS handshake with the server. It's your ssl client's job to find a matching trusted CA for the chain.

You have to add CA to CA_BUNDLE not leaf server cert.

How to get the CA cert? Try in your browser and click on the lock, the CA cert will be upmost in the chain if it's found.

You can also inspect the cert and find out who signed it (issuer attribute). Maybe you'll be able to find that issuer's cert in some public CA database.

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you for your answer.As suggested by you, I have already added CA, Intermediate and Leaf server certificate to cacert.pem of certifi. But I.m still getting the same error.
How did you obtain the certs? How did you verify that CA is actually the CA?
0

Try running the program code below:

# install_certifi.py # # sample script to install or update a set of default Root Certificates # for the ssl module. Uses the certificates provided by the certifi package: # https://pypi.python.org/pypi/certifi import os import os.path import ssl import stat import subprocess import sys STAT_0o775 = ( stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR | stat.S_IRGRP | stat.S_IWGRP | stat.S_IXGRP | stat.S_IROTH | stat.S_IXOTH ) def main(): openssl_dir, openssl_cafile = os.path.split( ssl.get_default_verify_paths().openssl_cafile) print(" -- pip install --upgrade certifi") subprocess.check_call([sys.executable, "-E", "-s", "-m", "pip", "install", "--upgrade", "certifi"]) import certifi # change working directory to the default SSL directory os.chdir(openssl_dir) relpath_to_certifi_cafile = os.path.relpath(certifi.where()) print(" -- removing any existing file or link") try: os.remove(openssl_cafile) except FileNotFoundError: pass print(" -- creating symlink to certifi certificate bundle") os.symlink(relpath_to_certifi_cafile, openssl_cafile) print(" -- setting permissions") os.chmod(openssl_cafile, STAT_0o775) print(" -- update complete") if __name__ == '__main__': main() 

4 Comments

When I tried this, I got: Traceback (most recent call last): File "b:\d\my\py\wget.py", line 55, in <module> update_cert_store() File "b:\d\my\py\wget.py", line 26, in update_cert_store os.chdir(openssl_dir) FileNotFoundError: [WinError 2] The system cannot find the file specified: 'C:\\Program Files\\Common Files\\SSL'
Try pip install certifi
Already had done that.
Then open a new question with a detailed step-by-step explanation of what you want to get and where your problem is, there you will describe the mistakes you have so it will be easier to help you.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.