Java MQTT 5.x Client with ssl certificate gets an error Unsupported protocol version when connecting to VerneMQ

|Hi All

I am having a problem getting my Java MQTT 5.x Client with ssl certificate gets an error Unsupported protocol version when connecting to VerneMQ
I am getting an error of
Unsupported protocol version. (132)
at org.eclipse.paho.mqttv5.client.internal.ExceptionHelper.createMqttException(ExceptionHelper.java:32)
at org.eclipse.paho.mqttv5.client.internal.ClientState.notifyReceivedAck(ClientState.java:1074)
at org.eclipse.paho.mqttv5.client.internal.CommsReceiver.run(CommsReceiver.java:153)
at java.base/java.lang.Thread.run(Thread.java:835)

Please see source code MQTTV5WithSSL.java list below

Note using JDK 12, SSLSocketFactory getSocketFactory(…) in my TestMQTTV3SSL.java class, I am able to publish and subscribe using to secure VerneM Broker. Using mosquitto_pub and mosquitto_sub client also work.

The VerneMQ’s console.log from /log directory does not tell log any client connection.
Can you please me know how I can configure VerneMQ, so I get client connection failure log

Can you please have a look at my maven pom dependencies and MQTTV5WithSSL.java
let me know what I missing.

Thank you for your help

Below are my Maven dependencies

org.eclipse.paho
org.eclipse.paho.client.mqttv3
1.2.2


org.eclipse.paho
org.eclipse.paho.mqttv5.client
1.2.5

org.bouncycastle bcpkix-jdk15on 1.64

TestMQTTV5SSL.java class code

public class TestMQTTV5WithSSL {

public static void main(String[] args) {

    String publishTopic = "sp/moc/bc/sdd/rt-veh/veh/1.0.1";
    String subscribeTopic = "sp/moc/#";
    String testResourcePath = "/opt/scats/mqtt_cert/";
    String serverUrl = "ssl://eveitsdsfew05.tmb.rta.nsw.gov.au:8885";
    String caFilePath = testResourcePath + "ca.crt";
    String clientCrtFilePath = testResourcePath + "client.crt";
    String clientKeyFilePath = testResourcePath + "client.key";


    //System.setProperty("javax.net.ssl.trustStore", caFilePath);
    //System.setProperty("javax.net.ssl.trustStorePassword", "changeit");
    System.setProperty("com.sun.jndi.ldap.object.disableEndpointIdentification", "true");

    //-Dcom.sun.jndi.ldap.object.disableEndpointIdentification=true

    MqttClient client;
    try {
        client = new MqttClient(serverUrl, "2");
        MqttConnectionOptions options = new MqttConnectionOptions();
        //options.setUserName(mqttUserName);
        //options.setPassword(mqttPassword.toCharArray());

        options.setConnectionTimeout(60);
        options.setKeepAliveInterval(60);

        SSLSocketFactory socketFactory = getSocketFactory(caFilePath,
                clientCrtFilePath, clientKeyFilePath, "scatsadmin");
        options.setSocketFactory(socketFactory);

        System.out.println("Get Options properties  " + options.getDebug());
        System.out.println("starting connect the server...");

        client.connect(options);
        System.out.println("connected!");
        Thread.sleep(1000);

        client.subscribe(subscribeTopic, 1);
        client.disconnect();
        System.out.println("disconnected!");


    } catch (MqttException me) {
        System.out.println("MQTT exception reason " + me.getReasonCode());
        System.out.println("MQTT exception msg " + me.getMessage());
        System.out.println("MQTT exception loc " + me.getLocalizedMessage());
        System.out.println("MQTT exception cause " + me.getCause());
        System.out.println("MQTT exception excep " + me);
        me.printStackTrace();

    } catch (Exception e) {
        e.printStackTrace();
    }

}

private static SSLSocketFactory getSocketFactory(final String caCrtFile,
                                                 final String crtFile, final String keyFile, final String password)
        throws Exception {
    Security.addProvider(new BouncyCastleProvider());

    // load CA certificate
    X509Certificate caCert = null;

    FileInputStream fis = new FileInputStream(caCrtFile);
    BufferedInputStream bis = new BufferedInputStream(fis);
    CertificateFactory cf = CertificateFactory.getInstance("X.509");


    while (bis.available() > 0) {
        //caCert = new SCATSX509Cert(bis);
        //Object cert = cf.generateCertificate(bis);

        //caCert = (X509Certificate)cert;
        caCert = (X509Certificate) cf.generateCertificate(bis);
        // System.out.println(caCert.toString());
    }
    System.out.println("caCert.hashCode() = " + caCert.hashCode());
    Collection<List<?>> caCertSANList = caCert.getSubjectAlternativeNames();

    if( caCertSANList != null ) {
        System.out.println("caCertSANList size = " + caCertSANList.size());
    } else {
        System.out.println("caCertSANList = " + caCertSANList);
    }



    // load client certificate
    bis = new BufferedInputStream(new FileInputStream(crtFile));
    X509Certificate crtCert = null;

    while (bis.available() > 0) {
        crtCert = (X509Certificate) cf.generateCertificate(bis);
        // System.out.println(caCert.toString());
    }
    System.out.println("crtCert.hashCode() = " + crtCert.hashCode());
    Collection<List<?>> crtCertSANList = crtCert.getSubjectAlternativeNames();

    if( crtCertSANList != null ) {
        System.out.println("crtCertSANList size = " + crtCertSANList.size());
    } else {
        System.out.println("crtCertSANList = " + crtCertSANList);
    }
    // load client private key
    PEMParser pemParser = new PEMParser(new FileReader(keyFile));
    Object object = pemParser.readObject();
    PEMDecryptorProvider decProv = new JcePEMDecryptorProviderBuilder()
            .build(password.toCharArray());
    JcaPEMKeyConverter converter = new JcaPEMKeyConverter()
            .setProvider("BC");

    KeyPair key;
    if (object instanceof PEMEncryptedKeyPair) {
        System.out.println("Encrypted key - we will use provided password");
        key = converter.getKeyPair(((PEMEncryptedKeyPair) object)
                .decryptKeyPair(decProv));
    } else if (object instanceof PrivateKeyInfo) {

        System.out.println("Unencrypted PrivateKeyInfo key - no password needed");

        PrivateKeyInfo privateKeyInfo = (PrivateKeyInfo) object;

        key = converter.getKeyPair((PEMKeyPair)privateKeyInfo.parsePrivateKey());

    }
    else {
        System.out.println("Unencrypted key - no password needed");
        key = converter.getKeyPair((PEMKeyPair) object);
    }


    pemParser.close();

    // CA certificate is used to authenticate server
    KeyStore caKs = KeyStore.getInstance(KeyStore.getDefaultType());
    caKs.load(null, null);
    caKs.setCertificateEntry("ca-certificate", caCert);
    TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509");
    tmf.init(caKs);

    // client key and certificates are sent to server so it can authenticate
    // us
    KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
    ks.load(null, null);
    ks.setCertificateEntry("certificate", crtCert);
    ks.setKeyEntry("private-key", key.getPrivate(), password.toCharArray(),
            new java.security.cert.Certificate[] { crtCert });
    KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory
            .getDefaultAlgorithm());
    kmf.init(ks, password.toCharArray());

    // finally, create SSL socket factory
    SSLContext context = SSLContext.getInstance("SSL");
    //SSLContext context = SSLContext.getInstance("TLSv1.2");
    context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), new SecureRandom());

    return context.getSocketFactory();
}

}

1 Like

Hi,
Your MQTT listener is not configured to accept protocol 132 (bridge).

As an MQTT client, I suppose you should not insist on bridge protocol if you are not a bridge.

2 Likes

Hi @afa

My Java MQTT 5.x Client with ssl certificate is not configured to accept protocol 132 (bridge) and failed to connect to VerneMQ cluster.
My Java MQTT 3.x Client with ssl certificate is not configured to accept protocol 132 (bridge), Its able to connect to VerneMQ and publish / subcribe messages.

I am kind of confuese as why My Java MQTT 5.x Client with ssl certificate failed to connect to VerneMQ.

Can you please advise what I should do to fix my My Java MQTT 5.x Client.

Thank you for your help

2 Likes

I do not immediately know. Check which protocols you have enabled for the MQTT listener in the vernemq.conf file.
Thank you for feedback, in case you find a solution.

2 Likes

Hi @afa

VerneMQ’s log show an error of vmq_mqtt5_fsm:init:202 invalid protocol version for {[],undefined}

What does this mean ?

Regards, Bao

1 Like

It indicates that the client wants to use a protocol version that is not allowed in the server configuration for that listener. I think the log line cited is incomplete; and you should actually see the protocol version logged. Add the protocol version you see there to the config:

listener.ssl.mylistener.allowed_protocol_versions = 3,4,5,131

2 Likes

Hi @afa

I finally solve the problem by setting

  • e “DOCKER_VERNEMQ_LISTENER__SSL__ALLOWED_PROTOCOL_VERSIONS=3,4,5”

By default VerneMQ set listener.ssl.allowed_protocol_versions=3

Thank you for your help

2 Likes