Python Websockets创建PEM文件

3

你好,我正在使用Python库Websockets。在开发过程中一切正常,但在服务器上它会崩溃,因为需要使用WSS。上面的链接给出了一个示例来说明如何做到这一点:

#!/usr/bin/env python

# WSS (WS over TLS) server example, with a self-signed certificate

import asyncio
import pathlib
import ssl
import websockets

async def hello(websocket, path):
    name = await websocket.recv()
    print(f"< {name}")

    greeting = f"Hello {name}!"

    await websocket.send(greeting)
    print(f"> {greeting}")

ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
localhost_pem = pathlib.Path(__file__).with_name("localhost.pem")
ssl_context.load_cert_chain(localhost_pem)

start_server = websockets.serve(
    hello, "localhost", 8765, ssl=ssl_context
)

asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()

这段代码很简单,但我不知道如何生成它所需的文件(服务器和客户端都需要)。我已经尝试了“创建PEM文件”,但没有结果,并且收到了各种各样的SSL错误。请有人能够解释一下如何为该应用程序创建PEM文件吗?谢谢。
编辑: 根据答案,我使用了……
sudo openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -keyout key.pem -out cert.pem

这样做会创建两个文件。

我现在成功地通过执行以下操作使服务器监听:

ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
path_cert = pathlib.Path(__file__).with_name("cert.pem")
path_key = pathlib.Path(__file__).with_name("key.pem")
ssl_context.load_cert_chain(path_cert, keyfile=path_key)

print("Listening for connection...")
start_server = websockets.serve(handler, HOSTNAME, PORT, ssl=ssl_context)

我唯一还遇到问题的部分是让客户端连接,我尝试了以下代码:
ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
path_cert = pathlib.Path(__file__).with_name("cert.pem")
ssl_context.load_cert_chain(path_cert)

async with websockets.connect(uri, ssl=ssl_context) as websocket:

但我收到了以下错误信息:ssl.SSLError: [SSL] PEM lib (_ssl.c:3854)

我还尝试过:

ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
path_cert = pathlib.Path(__file__).with_name("cert.pem")
path_key = pathlib.Path(__file__).with_name("key.pem")
ssl_context.load_cert_chain(path_cert, keyfile=path_key)

async with websockets.connect(uri, ssl=ssl_context) as websocket:

并且收到了错误消息:ssl.SSLCertVerificationError: [SSL:CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate (_ssl.c:1076)

编辑2: 根据答案,我尝试为客户端执行以下操作:

ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
ssl_context.load_verify_locations()

async with websockets.connect(uri, ssl=ssl_context) as websocket:

这会生成一个新的错误:TypeError: cafile、capath 和 cadata 不能全部省略 尝试第二个建议:
ssl_context = ssl.create_default_context()
ssl_context.load_verify_locations(certifi.where())

async with websockets.connect(uri, ssl=ssl_context) as websocket:

生成错误:ssl.SSLCertVerificationError:[SSL:CERTIFICATE_VERIFY_FAILED]证书验证失败:自签名证书(_ssl.c:1076)

编辑3: 最终工作客户端:

ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
path_cert = pathlib.Path(__file__).with_name("cert.pem")
ssl_context.load_verify_locations(path_cert)

async with websockets.connect(uri, ssl=ssl_context) as websocket:
1个回答

3

PEM文件包含公钥、私钥或证书的一些信息,并且它具有base64编码的数据位。PEM代表增强隐私邮件,用于邮件安全标准。它包括形式为

的头部和底部行。

如何创建PEM文件

如何创建自签名PEM文件。

openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -keyout key.pem -out cert.pem

如何从现有证书文件中创建一个 PEM 文件形成链。(可选)按照下面的步骤从私钥中删除密码:
openssl rsa -in server.key -out nopassword.key

如何通过自动化脚本创建PEM文件:
  1. 下载NetIQ Cool Tool OpenSSL-Toolkit。

  2. 选择Create Certificates | PEM with key and entire trust chain。

  3. 提供包含证书文件的完整路径。

  4. 提供以下文件的文件名:私钥、公钥(服务器crt)(有条件的)、私钥密码(有条件的)、任何中间证书链文件。

你将会得到类似这样的结果:
-----BEGIN RSA PRIVATE KEY----- 
(Private Key: domain_name.key contents) 
-----END RSA PRIVATE KEY-----
-----BEGIN CERTIFICATE----- 
(Primary SSL certificate: domain_name.crt contents) 
-----END CERTIFICATE----- 
-----BEGIN CERTIFICATE----- 
(Intermediate certificate: certChainCA.crt contents) 
-----END CERTIFICATE----

你可以对其进行解码:
openssl x509 -in cert.pem -text -noout

您将得到类似于以下内容:
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 0 (0x0)
    Signature Algorithm: ecdsa-with-SHA256
        Issuer: C = BE, O = GnuTLS, OU = GnuTLS certificate authority, ST = Leuven, CN = GnuTLS certificate authority
        Validity
            Not Before: May 23 20:38:21 2011 GMT
            Not After : Dec 22 07:41:51 2012 GMT
        Subject: C = BE, O = GnuTLS, OU = GnuTLS certificate authority, ST = Leuven, CN = GnuTLS certificate authority
        Subject Public Key Info:
            Public Key Algorithm: id-ecPublicKey
                Public-Key: (256 bit)
                pub:
                    04:52:d8:8d:23:8a:e3:67:d7:86:36:b1:20:0b:09:
                    7d:c8:c9:ba:a2:20:95:2f:c5:4a:63:fa:83:5f:ce:
                    78:2f:8f:f3:62:ca:fd:b7:f7:80:56:9d:6e:17:b9:
                    0e:11:4c:48:b2:c0:af:3b:59:17:16:30:68:09:07:
                    99:17:fe:dd:a7
                ASN1 OID: prime256v1
                NIST CURVE: P-256
        X509v3 extensions:
            X509v3 Basic Constraints: critical
                CA:TRUE
            X509v3 Key Usage: critical
                Certificate Sign, CRL Sign
            X509v3 Subject Key Identifier: 
                F0:B4:81:FE:98:12:BF:B5:28:B9:64:40:03:CB:CC:1F:66:4E:28:03
    Signature Algorithm: ecdsa-with-SHA256
         30:45:02:20:31:ae:c0:3d:4a:3f:21:be:85:17:fc:f0:c7:b2:
         31:07:2a:38:56:43:d1:36:d5:95:e1:7e:52:c0:06:43:87:a7:
         02:21:00:97:8c:0e:b8:3c:0a:41:af:ae:a5:cf:06:7e:d5:c4:
         d8:2f:ff:e2:62:80:34:10:ba:22:dd:35:81:46:93:22:9a

创建 PEM 文件

针对客户端部分,您编写了以下内容:

ssl_context.load_cert_chain(path_cert, keyfile=path_key)

替换它:

import json
import asyncio
import websockets
import ssl
import certifi


ssl_context = ssl.create_default_context()
ssl_context.load_verify_locations(certifi.where())


query =  {
    "jsonrpc": "2.0",
    "method": "queryHeadsets",
    "params": {},
    "id": 1
    }
json = json.dumps(query)

async def query(json):

    async with websockets.connect("wss://yourserver.com:54321", ssl=ssl_context) as ws:
        await ws.send(json)
        response = await ws.recv()
        print(response)

asyncio.get_event_loop().run_until_complete(query(json))

在第三步,那个目录里应该有哪些文件? - Tristan Neate
这取决于您是否有现有的证书文件,我已经更新了我的答案。 - Mahsa Hassankashi
服务器现在正常工作,谢谢。您能否查看我的编辑并帮助客户端? - Tristan Neate
很好,在您的客户端代码中替换SSLContext.load_verify_locations()。 - Mahsa Hassankashi
我尝试了两种方法,但都没有成功,我在编辑中添加了错误。 - Tristan Neate
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接