Search code examples
python-3.xpython-requestspempkipyopenssl

OpenSSL SSL:CERTIFCATE_VERIFY_FAILED


I'm trying to issue a get request to a https url which has a restful api that will respond back with an image that I wish to save off. I'm using python 3.5 on windows and the requests lib to make the https request.

I'm on a network in which every user is issued a pcks#12(.p12) cert and must install it in their browser to visit pretty much any of the webpages on the network including the site I'm targeting. Through my browser I am able to access the target website and download the image as desired. However, doing so programmatically has been a challenge.

I keep getting a SSL: CERTIFICATE_VERIFY_FAILED error. I can't copy the whole trace (its on a different computer) but below is a gist of what gets spit out in python console.

ssl.py, line 628, in do_handshake ssl.SSLError [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:645)

During handling of the above exception, another exception occurred: requests\adapters.py, line 447, in send*

raise SSLError(e, request=request) requests.exceptions.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:645)

Here is my code. I'm converting from .p12 to .pem because I believe that is what the requests library requires.

Password = bytes(r'blahblahblah','utf-8')
P12 = OpenSSL.crypto.load_pkcs12(open("C:/Temp/certs/mypki.p12",'rb').read(),password)

key = OpenSSL.crypto.dump_privatekey(OpenSSL.crypto.FILETYP_PEM, p12.get_privatekey())

mycert = OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYP_PEM, p12.get_certificate())

#len(get_ca_certificates) return 2 so I know I've got all of them
cert1 = OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYP_PEM, p12.get_ca_certificates()[0])

cert2 = OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYP_PEM, p12.get_ca_certificates()[1])

At one point I was getting errors saying that I had a key mismatch. This code led me to the discovery that the get_certificate() method returns a certificate not found in the tuple returned by the get_ca_certificate() method. Which was the matching public key to my private key. I'm just including this so people know I got a matching key pair.

k = OpenSSl.crypto.Load_privatekey(OpenSSL.crypto.FILETYPE_PEM,key)
c = OpenSSl.crypto.Load_certificate(OpenSSL.crypto.FILETYPE_PEM,mycert)

context = OpenSSL.SSL.Context(OpenSSL.SSL.TLSv1_1_METHOD)
context.use_privatekey(k)
context.use_certificate(c)

try:
   context.check_privatekey()
   return True
except OpenSSL.SSL.Error:
   return FALSE

I've decided to create a .pem file with my key and certs all in one file. I've also tried separating the key from certs in different files but get the same error when doing so. I'm not 100% clear on the differences between .pem,.crt, etc and when to use which but I think I'm doing it correctly...?

pem_file = open("C:/Temp/Certs/cert.pem","wb")
pem_file.write(key)
pem_file.write(mycert)
pem_file.write(cert1)
pem_file.write(cert2)
pem_file.close()

 response = request.get("https://somewebsite.com",proxies={"http": None, 
"https:": None}, cert=("C:/Temp/Certs/cert.pem"))

For the sake of completeness this is the code I used when I tried writing out the key and certs to separate files.

response = request.get("https://somewebsite.com",proxies={"http": None, 
"https:": None}, cert=("C:/Temp/Certs/cert.crt" , "C:/Temp/Certs/key.key"))

Solution

  • So the issue ended up being I was using the wrong pcks#12 file. I was given a digital_signature.p12 and a encryption_key.p12 (or something like that) and the website was expecting the private key and certs from the digital_signature.p12 instead of the other one I was using.