certificate verify failed: unable to get local issuer certificate nothing seems wrong

43 Views Asked by At

i am using requests in python and i have the error

certificate verify failed: unable to get local issuer certificate

Here is my code :

import requests

url = 'https://sha256.badssl.com'

cert_path = 'certificate.pem'

response = requests.get(url, verify=cert_path)

The file certificate.pem contains -----BEGIN CERTIFICATE----- ... -----END CERTIFICATE----- as the result of

openssl s_client -connect sha256.badssl.com:443

certificate.pem is in the same directory as my main.py.

I tried with absolute path.

I tried woth 3.10.12 and 3.12.2

I already took a look at the doc and at the same isssue here.

I tried using another wifi.

I do not have any proxy running.

2

There are 2 best solutions below

0
Titouan Bernot On BEST ANSWER

that command:

openssl s_client -showcerts -connect sha256.badssl.com:443 < /dev/null > certificate

provides 2 certificates, requests needs the third one to get it on firefox there's that way :

click on padlock

click on view certificates

click on PEM(cert) in the 3rd certificate section

I didn't found how to get it with openssl tho. If anyone knows how to do it that would be helpfull

1
larsks On

I think you have multiple problems, because https://badssl.com has a valid certificate, so you should not be getting a certificate error for that URL. That suggests you're missing the basic list of trusted certificate authorities.

That said, let's take a closer look at the problem.

If you fetch the server certificate by doing something like this:

openssl s_client -connect sha256.badssl.com:443 < /dev/null > certificate

Then you get a single certificate:

$ grep BEGIN certificate
-----BEGIN CERTIFICATE-----

That certificate is not a self-signed certificate:

$ openssl x509 -in certificate -noout -subject -issuer certificate
subject=CN = *.badssl.com
issuer=C = US, O = Let's Encrypt, CN = R3

That means it doesn't make any sense to use it in the verify parameter of requests.get; you need the certificate of the issuer. You may need more than, when using openssl s_client to fetch a remote certificate, you need to provide the -showcerts option, which will display the entire certificate chain sent by the server:

openssl s_client -showcerts -connect sha256.badssl.com:443 < /dev/null > certificate

Now you will find that we have multiple certificates:

$ grep BEGIN certificate
-----BEGIN CERTIFICATE-----
-----BEGIN CERTIFICATE-----

The first certificate is the one we've already seen, but the second is for:

subject=C = US, O = Let's Encrypt, CN = R3
issuer=C = US, O = Internet Security Research Group, CN = ISRG Root X1

And if we use this new file as our CA bundle, it works as expected:

>>> import requests
>>> requests.get('https://badssl.com/', verify='certificate')
<Response [200]>

It's worth noting that the certificate chain presented by the remote server may not include the root certificate. In that case, you would need to fetch the root certificate directly from the certificate authority (e.g. https://letsencrypt.org/certificates/ for Let's Encrypt).