2

At the moment I am trying to figure out how to do an MQTT publish using the .crt and .pem files for our application.

below is some pseudo code for what I am trying to do: connect to an existing topic over tls publish a message

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)

When I run the script the following error is thrown:

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:\Python27\lib\site-packages\paho\mqtt\client.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

I read through the TLS example on the paho doc page, but just do not understand how I should be passing the crt / pem files in my code. At one point I was only pointing to the folder containing the files, and even went as far as to chmod 777 the folder but at that point I was getting access denied from python at run time.

Any help is appreshiated

Lombax
  • 851
  • 4
  • 9
  • 25

2 Answers2

4

Do you want to do TLS client authentication (that is, your Python script needs to authenticate to the server / MQTT broker)? Or do you want your Python script to behave like a web browser, and just validate the server certificate?

If you only want the latter, I have had success using the tls_set() method in the Paho Python client when I point it to a PEM file containing the server's certificate. And that's the only argument you need to pass on tls_set() to have the Paho client validate the server certificate, and connect to the broker using TLS. For example:

mqttc.tls_set("/home/bob/certificates/mqttbrokercertificate.pem")

How do you obtain the mqtt broker's certificate in PEM format? The easiest way is with openssl:

openssl s_client -host mqtt.broker.hostname.com -port 8883 -showcerts

Redirect the output to a file, and delete every line in the file except what is between the "BEGIN CERTIFICATE" and "END CERTIFICATE" lines (inclusive -- be sure to include these lines as well). This is a good article here on StackOverflow about how to save a server's SSL certificate using openssl:

How to save server SSL certificate to a file

Lastly, you need to be sure of what version of TLS your broker supports, and make sure your Python client also supports it. For example, the IBM Watson IoT Platform requires TLS 1.2. The ssl module in Python 2.7 (which is built on openssl) does not support TLS 1.2. Generally, you need Python 3.X, and openssl of at least 1.0.1. Here is how you can set the TLS version on the Paho client (don't forget to import ssl):

 mqttc.tls_set("/home/bob/certificates/mqttbrokercertificate.pem", tls_version=ssl.PROTOCOL_TLSv1_2)

If you want TLS client authentication, that's probably better handled in an entirely separate article. But I hope this helps with TLS server authentication using the Paho Python client.

Community
  • 1
  • 1
Henry DeAngelis
  • 191
  • 1
  • 9
  • Is there no way to directly pass the trusted CA path in tls_sety function as done in this command - mosquitto_sub -h HOSTNAME -t test -p 8883 --capath /etc/ssl/certs/ -u "abc -P "abc" ? – Rahul Gusai Aug 13 '20 at 06:59
2

Looking at the error it would suggest that the tls_set function is expecting paths to the files not the contents of the file to be passed in.

hardillb
  • 54,545
  • 11
  • 67
  • 105