目前,我正在尝试弄清楚如何使用应用程序的.crt和.pem文件进行MQTT发布。
下面是我正在尝试执行的操作的一些伪代码:通过 TLS 连接到现有主题发布消息
import paho.mqtt.publish as mqtt
import paho.mqtt.client as mqttclient
topic = "Some/Topic/Goes/Here"
my_ca_cert = open("<path_to_cert>ca.crt", 'rb').read()
my_pri_cert = open("<path_to_cert>private.pem", 'rb').read()
my_key_cert = open("<path_to_cert>certificate.pem", 'rb').read()
mqttc = mqttclient.Client("Python_Ex_Pub")
mqttc.tls_set(my_ca_cert, certfile=my_pri_cert, keyfile=my_key_cert)
mqttc.connect("<gateway_address>", 8883)
mqttc.publish(topic_name, "This is a test pub from Python.")
mqttc.loop(timeout=2.0, max_packets=1)
当我运行脚本时,抛出以下错误:
Traceback (most recent call last):
File "mqtt_pub_test.py", line 9, in <module>
mqttc.tls_set(my_ca_cert, certfile=my_pri_cert, keyfile=my_key_cert)
File "C:Python27libsite-packagespahomqttclient.py", line 557, in tls_set
raise IOError(ca_certs+": "+err.strerror)
IOError: -----BEGIN CERTIFICATE-----
<cert_info_here>
-----END CERTIFICATE-----: No such file or directory
我通读了 paho 文档页面上的 TLS 示例,但只是不明白我应该如何在代码中传递 crt/pem 文件。有一次我只指向包含文件的文件夹,甚至去了 chmod 777 文件夹,但那时我在运行时被拒绝了来自 python 的访问。
任何帮助都得到赞赏
是否要进行TLS客户端认证(即您的Python脚本需要向服务器/MQTT代理进行身份验证)? 或者您希望您的 Python 脚本像 Web 浏览器一样运行,并且只验证服务器证书?
如果您只想要后者,当我在 Paho Python 客户端中使用 tls_set() 方法时,我已经成功地将其指向包含服务器证书的 PEM 文件。 这是您需要传递 tls_set() 以使 Paho 客户端验证服务器证书并使用 TLS 连接到代理的唯一参数。例如:
mqttc.tls_set("/home/bob/certificates/mqttbrokercertificate.pem")
如何获取 PEM 格式的 MQTT 代理证书? 最简单的方法是使用 openssl:
openssl s_client -host mqtt.broker.hostname.com -port 8883 -showcerts
将输出重定向到文件,并删除文件中除"开始证书"和"结束证书"行(包括 - 确保也包括这些行)之间的每一行。 这是一篇关于StackOverflow的好文章,介绍如何使用openssl保存服务器的SSL证书:
如何将服务器 SSL 证书保存到文件
最后,您需要确定您的代理支持哪个版本的 TLS,并确保您的 Python 客户端也支持它。 例如,IBM Watson IoT Platform 需要 TLS 1.2。 Python 2.7 中的 ssl 模块(基于 openssl 构建)不支持 TLS 1.2。 一般来说,你需要Python 3.X,并且至少需要1.0.1的openssl。 以下是在 Paho 客户端上设置 TLS 版本的方法(不要忘记导入 ssl):
mqttc.tls_set("/home/bob/certificates/mqttbrokercertificate.pem", tls_version=ssl.PROTOCOL_TLSv1_2)
如果需要 TLS 客户端身份验证,最好在完全单独的文章中处理。 但我希望这有助于使用 Paho Python 客户端进行 TLS 服务器身份验证。
查看错误,它表明tls_set函数需要文件的路径,而不是要传入的文件内容。