Allen Xu
Allen Xu

Reputation: 143

Python Paho-mqtt client with server side certificate problem

My python paho-mqtt client failed to connect to broker which written in java. The broker has enabled SSL connection with a jks type cert. The broker is beyond my administration.

I convert the jks cert to pem cert to use in my python code. But when I run the code, there is an error:

Traceback (most recent call last):
  File "test.py", line 55, in <module>
    client.connect("192.168.110.2", 56785, 60)
  File "C:\Python\Python37\lib\site-packages\paho\mqtt\client.py", line 760, in
connect
    return self.reconnect()
  File "C:\Python\Python37\lib\site-packages\paho\mqtt\client.py", line 919, in
reconnect
    sock.do_handshake()
  File "C:\Python\Python37\lib\ssl.py", line 1117, in do_handshake
    self._sslobj.do_handshake()
ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: CA signature digest algorithm too weak (_ssl.c:1056)

So I think there is a problem with the cert. How can I bypass the CA signature digest algorithm check?

I converted the jks cert to pem cert with following commands:

keytool -importkeystore -srckeystore server.jks -destkeystore server.p12 -srcstoretype jks -deststoretype pkcs12
openssl pkcs12 -in server.p12 -out server.pem

Here is my full code:

# -*- coding:utf-8 -*-

import json
import ssl
import time

import paho.mqtt.client as mqtt

# constants
token = 'token '
mqtt_username = 'name'
mqtt_passwd = 'pass'

test_payload = {"type": "a_type","data": "my data","tokens": [token]}


def on_connect(client, userdata, flags, rc):
    print("Connected with result code " + str(rc))
    if rc == 0:
        # subscribe
        client.subscribe("Client/%s/Biz/Down" % token, 1)
        time.sleep(3)
        client.publish('Client/%s/Biz/Up' % token,
                       json.dumps(test_payload))
    # time.sleep(5)
    else:
        client.disconnect()


def on_message(client, userdata, msg):
    print(msg.topic + " " + str(msg.payload))
    if ("Client/%s/Biz/Down" % token) == msg.topic:
        client.disconnect()


client = mqtt.Client('', True, None, mqtt.MQTTv31)
client.username_pw_set(mqtt_username, mqtt_passwd)
client.on_connect = on_connect
client.on_message = on_message
client.tls_set('./server.pem')

client.connect("192.168.110.2", 56785, 60)

client.loop_forever()

Upvotes: 1

Views: 4808

Answers (2)

Daniel
Daniel

Reputation: 1

I needed to use a different version of the TLS protocol.

MQTTversion = mqtt.MQTTv31
TLS_protocol_version = ssl.PROTOCOL_TLSv1_2

Next my code sample.

import requests
from requests.models import HTTPBasicAuth, Response, StreamConsumedError
from requests import Request, Session
import paho.mqtt.client as mqtt
from paho.mqtt import client
import ssl

External_MQTT_Server = False
External_MQTT_Host = "test.mosquitto.org"
External_MQTT_User = "nda"
External_MQTT_Pass = "nda"
External_MQTT_TLS = False
External_MQTT_TLS_PORT = 8883   

# mqqt SSL
MQTTversion = mqtt.MQTTv31
TLS_protocol_version = ssl.PROTOCOL_TLSv1_2

paho_erro_codes = {0: "Connection successful",
    1: "Connection refused – incorrect protocol version",
    2: "Connection refused – invalid client identifier",
    3: "Connection refused – server unavailable",
    4: "Connection refused – bad username or password",
    5: "Connection refused – not authorised",
    100: "Connection refused - other things"
}

def mqttStart():
    ''' Start MQTT '''
    global client
    global clientOk
    # MQTT Start
    client = mqtt.Client(client_id = '', clean_session = True, userdata = None, protocol = MQTTversion, transport="tcp" )

    log().info("Starting MQTT " + MQTT_HOST)

    log().debug("mqttStart External: " + str(External_MQTT_Server))
    log().debug("mqttStart TLS: " + str(External_MQTT_TLS))
    log().debug("mqttStart MQTT_USERNAME: " + str(MQTT_USERNAME))
    log().debug("mqttStart MQTT_PASSWORD: " + str(MQTT_PASSWORD))
    log().debug("mqttStart MQTT_PORT: " + str(MQTT_PORT))
    client.username_pw_set(username=MQTT_USERNAME, password=MQTT_PASSWORD)
    client.on_connect = on_connect
    # client.on_message = on_message
    client.on_disconnect = on_disconnect
    client.on_publish = on_publish
    client.on_log = on_log
    log().debug("Trying TLS: " + str(MQTT_PORT))
    context = ssl.SSLContext(protocol = TLS_protocol_version) 
    client.tls_set_context(context)
    try:
        clientOk = True
        #rc = client.connect(MQTT_HOST, MQTT_PORT, 60) # 1883
        rc = client.connect(host = MQTT_HOST,
            port = MQTT_PORT,
            keepalive = 60)  # 1883
    except Exception as e:  # OSError
        if e.__class__.__name__ == 'OSError':
            clientOk = False
            log().warning("Can't start MQTT")
        else:
            clientOk = False
    if clientOk:  client.loop_start()  # start the loop

def on_connect(client, userdata, flags, rc):
    global gConnected
    global status

    print("MQTT connected with result code " + str(rc))
    if rc == 0:
        print ("Connected to " + MQTT_HOST)
        gConnected = True
        client.connected_flag = True
    else:
        gConnected = False
        if rc>5: rc=100
        print (str(rc) + paho_erro_codes[rc])
        log().error(str(rc) + str(paho_erro_codes[rc]))
        if rc == 4 or rc == 5:
            # wrong password
            print( "APP EXIT" + str(rc))
            time.sleep(60000)

def on_log(client, userdata, level, buf):
  print("log: ",buf)


def on_disconnect(client, userdata, rc):
    global gConnected
    global gDevices_enviados
    global status
    gConnected = False
    log().info("disconnecting reason  "  +str(rc) + str(paho_erro_codes[rc]))
    print("disconnecting reason  "  +str(client) )
    client.connected_flag=False
    client.disconnect_flag=True

Upvotes: 0

Allen Xu
Allen Xu

Reputation: 143

I have figured it out. On client side, you do not need to configure server's self-signed cert. Now it worked!

# -*- coding:utf-8 -*-

import json
import ssl
import time

import paho.mqtt.client as mqtt

# constants
token = 'token '
mqtt_username = 'name'
mqtt_passwd = 'pass'

test_payload = {"type": "a_type","data": "my data","tokens": [token]}


def on_connect(client, userdata, flags, rc):
    print("Connected with result code " + str(rc))
    if rc == 0:
        # subscribe
        client.subscribe("Client/%s/Biz/Down" % token, 1)
        time.sleep(3)
        client.publish('Client/%s/Biz/Up' % token,
                       json.dumps(test_payload))
    # time.sleep(5)
    else:
        client.disconnect()


def on_message(client, userdata, msg):
    print(msg.topic + " " + str(msg.payload))
    if ("Client/%s/Biz/Down" % token) == msg.topic:
        client.disconnect()


client = mqtt.Client('', True, None, mqtt.MQTTv31)
client.username_pw_set(mqtt_username, mqtt_passwd)
client.on_connect = on_connect
client.on_message = on_message

# the key steps here
context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
# if you do not want to check the cert hostname, skip it
# context.check_hostname = False
client.tls_set_context(context)

client.connect("192.168.110.2", 56785, 60)

client.loop_forever()

Upvotes: 2

Related Questions