python - 如何使用带有 python 的智能卡发出 TLS 请求?

标签 python ssl python-requests pkcs#11

我尝试使用 python 库“requests”与受智能卡保护的网站进行通信。这意味着 SSL 中的强身份验证:您必须提供客户端证书(证书和私钥)。

因为我使用的是智能卡,所以我无法读取属于正常保护的私钥(只能读取模数)。我可以使用 python 库 PyKCS11 读取智能卡:一旦给出 pin 码,所有证书、公钥和私钥模数。

如何混合请求和 PyKCS11?
如何使用智能卡中的客户端证书发出 SSL 请求?

编辑 2017/08/04

在我的 Mac 上:

  • brew 安装 openssl
  • brew 安装 opensc
  • 酿造安装engine_pkcs11
  • 打开SSL
    • engine dynamic -pre SO_PATH:/usr/local/Cellar/engine_pkcs11/0.1.8/lib/engines/engine_pkcs11.so -pre ID:pkcs11 -pre LIST_ADD:1 -pre LOAD -pre MODULE_PATH:/usr/local/lib/(我特定的 Pkcs11 库).dylib
      • 已加载:(pkcs11) pkcs11 引擎
    • s_client -engine pkcs11 -key '(slot):(id)' -keyform engine -cert 'pem.cer' -connect (host):443 -state -debug
      • SSL 握手成功

我现在的问题是 pyOpenSSl 在 API 中没有选择引擎的功能(比如 pkcs11)。所以我停下来了。我不能使用 python。

最佳答案

我有一个类似的问题,除了我在 Windows 上并且需要使用“capi”引擎来处理智能卡客户端证书。我有一个使用 cffi 的工作代码和使用 pyopenssl 的请求,我希望更改它以支持 pkcs11 应该不会太困难。

import os
import ssl
import sys

import cffi
import requests

pyopenssl = requests.packages.urllib3.contrib.pyopenssl
pyopenssl.inject_into_urllib3()

# I use anaconda and these paths are valid for me, change as required
libcryptopath = os.path.join(sys.prefix, "Library", "bin", "libcrypto-1_1-x64.dll")
libsslpath = os.path.join(sys.prefix, "Library", "bin", "libssl-1_1-x64.dll")
capipath = os.path.join(sys.prefix, "Library", "lib", "engines-1_1", "capi.dll")

ffi = cffi.FFI()
ffi.cdef(
    "void *ENGINE_by_id(const char *id);"
    "int ENGINE_ctrl_cmd_string(void *e, const char *cmd_name, const char *arg, int cmd_optional);"
    "int ENGINE_init(void *e);"
    "int SSL_CTX_set_client_cert_engine(void *ctx, void *e);"
)

try:
    libcrypto, libssl, engine
except NameError:
    libcrypto = ffi.dlopen(libcryptopath)
    libssl = ffi.dlopen(libsslpath)
    engine = libcrypto.ENGINE_by_id(b"dynamic")
    libcrypto.ENGINE_ctrl_cmd_string(engine, b"SO_PATH", capipath.encode(), 0)
    libcrypto.ENGINE_ctrl_cmd_string(engine, b"LOAD", ffi.NULL, 0)
    libcrypto.ENGINE_init(engine)


class PyOpenSSLContextCAPI(pyopenssl.PyOpenSSLContext):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        libssl.SSL_CTX_set_client_cert_engine(self._ctx._context, engine)


# https://lukasa.co.uk/2017/02/Configuring_TLS_With_Requests/
class HTTPAdapterCAPI(requests.adapters.HTTPAdapter):
    def init_poolmanager(self, *args, **kwargs):
        context = PyOpenSSLContextCAPI(ssl.PROTOCOL_TLS)
        kwargs['ssl_context'] = context
        return super().init_poolmanager(*args, **kwargs)


class SessionCAPI(requests.Session):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.mount("https://", HTTPAdapterCAPI())


if __name__ == '__main__':
    s = SessionCAPI()
    r = s.get("https://example.com")
    print(r.text)

关于python - 如何使用带有 python 的智能卡发出 TLS 请求?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45385964/

相关文章:

java - 如何调用 AWS Lambda 函数的 ssl 端点

python - 如何在 python 列表中创建和比较 JSON 值

python - 如何加速数百万对象的python实例初始化?

PHP 连接到 Postgresql 错误

ssl - Libvirt 和 TLS 忽略 CA 文件设置

python - 如何使用 python 库登录需要 cookie 的站点

Python - Mailchimp 批量 PUT 请求

python - 查找数组是否包含 2 旁边的 2

作为 Windows 服务的 Python Flask

python - python 中的 for 循环比 matlab 慢 10 倍