OpenSSL SSL:CERTIFCATE_VERIFY_FAILED

OpenSSL SSL:CERTIFCATE_VERIFY_FAILED

我正在尝试向 https url 发出一个获取请求,其中有一个 restful api,它将以我希望保存的图像作为响应。我在 windows 上使用 python 3.5 和请求库来发出 https 请求。

我所在的网络向每个用户颁发了 pcks#12(.p12) 证书,并且必须将其安装在他们的浏览器中才能访问网络上的几乎所有网页,包括我所在的网站瞄准。通过我的浏览器,我可以访问目标网站并根据需要下载图像。然而,以编程方式这样做一直是一个挑战。

我不断收到 SSL: CERTIFICATE_VERIFY_FAILED 错误。我无法复制整个跟踪(它在另一台计算机上),但下面是在 python 控制台中吐出的内容的要点。

ssl.py,第 628 行,在 do_handshake ssl.SSLError [SSL: CERTIFICATE_VERIFY_FAILED] 证书验证失败(_ssl.c:645 )

在处理上述异常的过程中,又出现了一个异常: requests\adapters.py,第 447 行,在发送*

引发 SSLError(e, request=request) requests.exceptions.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] 证书验证失败 (_ssl.c:645)

这是我的代码。我正在从 .p12 转换为 .pem,因为我相信这是请求库所需要的。

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])

有一次我收到错误消息说我的密钥不匹配。这段代码让我发现 get_certificate() 方法 returns 在 get_ca_certificate() 方法返回的元组中找不到证书。这是与我的私钥匹配的 public 密钥。我只是包括这个,所以人们知道我有一个匹配的密钥对。

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

我决定创建一个 .pem 文件,将我的密钥和证书全部放在一个文件中。我也尝试过将密钥与不同文件中的证书分开,但这样做时会出现相同的错误。我不是 100% 清楚 .pem、.crt 等之间的区别以及何时使用它们,但我认为我做的是正确的......?

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"))

为了完整起见,这是我在尝试写出密钥和证书以分隔文件时使用的代码。

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

所以问题最终是我使用了错误的 pcks#12 文件。我得到了一个 digital_signature.p12 和一个 encryption_key.p12(或类似的东西),该网站期待来自 digital_signature.p12 而不是另一个的私钥和证书我在用。