What does "SSLError: [SSL] PEM lib (_ssl.c:2532)" mean using the Python ssl library?

What does "SSLError: [SSL] PEM lib (_ssl.c:2532)" mean using the Python ssl library?

我正在尝试使用 Python 3 asyncio 模块连接到另一方并收到此错误:

     36     sslcontext = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
---> 37     sslcontext.load_cert_chain(cert, keyfile=ca_cert)
     38

SSLError: [SSL] PEM lib (_ssl.c:2532)

问题只是错误的含义。我的证书是正确的,密钥文件(CA 证书)可能不

假设使用的是 3.6 版:

参见:https://github.com/python/cpython/blob/3.6/Modules/_ssl.c#L3523-L3534

 PySSL_BEGIN_ALLOW_THREADS_S(pw_info.thread_state);
 r = SSL_CTX_check_private_key(self->ctx);
 PySSL_END_ALLOW_THREADS_S(pw_info.thread_state);
 if (r != 1) { 
    _setSSLError(NULL, 0, __FILE__, __LINE__);
    goto error;
 }

意思是SSL_CTX_check_private_key失败了;因此,私钥不正确。

参考可能的版本:

在您的代码中,您正在调用:

sslcontext.load_cert_chain(cert, keyfile=ca_cert)

来自documentation

Load a private key and the corresponding certificate. The certfile string must be the path to a single file in PEM format containing the certificate as well as any number of CA certificates needed to establish the certificate’s authenticity. The keyfile string, if present, must point to a file containing the private key in. Otherwise the private key will be taken from certfile as well. See the discussion of Certificates for more information on how the certificate is stored in the certfile.

根据您的示例中的参数名称,您似乎正在将 CA 证书传递给 keyfile 参数。这是不正确的,您需要传入用于生成本地证书的私钥(否则客户端无法使用您的证书)。私钥文件类似于:

-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,9BA4973008F0A0B36FBE1426C198DD1B

...data...
-----END RSA PRIVATE KEY-----

只有当您尝试验证由该证书签署的 SSL 证书的有效性时,您才需要 CA 证书。在那种情况下,您可能会使用 SSLContext.load_verify_locations() 来加载 CA 证书(尽管我最近没有使用 SSL 模块,所以请不要相信我的话)。

该错误表示缺少私钥文件。 在openssl中生成密钥对shell: openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365

启动 Python SSL 服务器:

from http.server import HTTPServer, 
             SimpleHTTPRequestHandler

import ssl

httpd = HTTPServer(('localhost', 4443), 
                           SimpleHTTPRequestHandler)

httpd.socket = ssl.wrap_socket(httpd.socket, 
                 certfile='/tmp/cert.pem',keyfile='
                           /tmp/key.pem', server_side=True)

httpd.serve_forever()

(我们使用端口 4443 以便我可以 运行 作为普通用户进行测试;通常的端口 443 需要 root 权限)。

在使用 openssl 生成受密码保护的自签名证书后,我遇到了类似的问题,我得到了以下输出:

ontext.load_cert_chain(certfile= certificate_private, keyfile= certificate)
ssl.SSLError: [SSL] PEM lib (_ssl.c:4012)

为了理解 load_cert_chain 上的文档阅读了两遍之后,我想到了以下解决方案:

import ssl
    
context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
context.load_cert_chain(certfile= certificate_private, keyfile= certificate_key, password= certificate_password)

connection = http.client.HTTPSConnection(host, port=443, context=context)
connection.request(method="POST", url=request_url, headers=request_headers, body=json.dumps(request_body_dict))
response = connection.getresponse()

其中证书文件是 cert.pem
密钥文件是 key.pem
密码是我生成自签名证书时使用的密码,类似于 .

在我的例子中,这个错误意味着我的证书有错误的文件扩展名。我必须使用以下方法将 cert.der 文件转换为 cert.pem 文件:

openssl x509 -inform der -in cert.der -out cert.pem