requests(截止2.12.4)不支持p12格式的证书,如果拿到的是p12证书可以转换为pem格式再使用。
查看p12证书
keytool -v -list -storetype pkcs12 -keystore your_pkcs.p12 -storepass your_password
转换为pem格式
# 证书和私钥一个文件保存
openssl pkcs12 -in your_pkcs.p12 -out client.pem
# 证书和私钥分开
openssl pkcs12 -in your_pkcs.p12 -out client_certs.pem -clcerts -nokeys [password options]
openssl pkcs12 -in your_pkcs.p12 -out keys.pem -nocerts [password options]
使用示例
import requests
req = requests.get('https://x.x.x.x/uri', cert='client.pem', verify=False)
# or
# req = requests.get('https://x.x.x.x/uri', cert=('client_certs.pem', 'keys.pem'), verify=False)
这里有个问题,只能支持没有密码的证书,否则会要求输入证书密码。
两种解决方法
1)不加密私钥,转换pem时,用-nodes放弃加密,硬编码和没密码差别不大
openssl pkcs12 -in your_pkcs.p12 -out client.pem -nodes
openssl pkcs12 -in your_pkcs.p12 -out keys.pem -nocerts -nodes
2)以下方法需要一些包(pyOpenSSL,ndg-httpsclient, pyasn1)以及N多依赖包,未测试
pkcs12_data = ...
password_bytes = ...
class Pkcs12Context(requests.packages.urllib3.contrib.pyopenssl.OpenSSL.SSL.Context):
def __init__(self, method):
super(PasswordContext, self).__init__(method)
p12 = OpenSSL.crypto.load_pkcs12(pkcs12_data, password_bytes)
self.use_certificate(p12.get_certificate())
self.use_privatekey(p12.get_privatekey())
# Monkey-patch the subclass into OpenSSL.SSL so it is used in place of the stock version
requests.packages.urllib3.contrib.pyopenssl.OpenSSL.SSL.Context = Pkcs12Context
3)还可以等待官方支持
参考
http://stackoverflow.com/questions/4372291/python-ssl-with-pkcs12-certificates
https://github.com/kennethreitz/requests/issues/1573