如何使用自签名证书连接到Android(paho客户端)中的Mqtt服务器? [英] How to use a self signed certificate to connect to a Mqtt server in Android (paho client)?

查看:183
本文介绍了如何使用自签名证书连接到Android(paho客户端)中的Mqtt服务器?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在使用自签名证书连接到mqtt服务器时遇到问题。即时通讯使用Paho客户端,并希望使用 TLSv1.2 连接到服务器。实际上我已成功连接Android API 20+但在此版本之下没有成功。

Im having problem connecting to a mqtt server using self signed certificate. im using Paho client and want to connect to a server using a TLSv1.2. actually i was successful to connect in Android APIs 20+ but no success for below this version.

到目前为止我做过的事情:

what ive done till now :

1-创建了一个PKCS#12密钥库并放入.crt文件并为其提供密码并保存(它将是.pfx文件)

1- created a PKCS#12 keystore and put the .crt file and assing a password to it and save it (it will be a .pfx file)

2-将.pfx文件添加到android项目中的原始文件夹中

2- added the .pfx file to raw folder of recourse in android project

3-下面的代码用于加载自签名证书:

3- used below code to load self signed certificate:

connection = createConnection(mqttCallback);

MqttConnectOptions connOpts = optionsFromModel(connectionModel);

connOpts.setSocketFactory(getSSLSocketFactory(keyStoreInputStream, keyStorePassword));

connection.addConnectionOptions(connOpts);

getSSLSocketFactory 方法是最多的重要的部分是:

and the getSSLSocketFactory method which is the most important part is :

    public SSLSocketFactory getSSLSocketFactory (InputStream keyStore, String password) throws MqttSecurityException {
    try{

        SSLContext ctx = null;
        SSLSocketFactory sslSockFactory=null;

        KeyStore ks;
        ks = KeyStore.getInstance("PKCS12");
        ks.load(keyStore, password.toCharArray());

        TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509");
        tmf.init(ks);
        TrustManager[] tm = tmf.getTrustManagers();
        ctx = SSLContext.getInstance("TLS");
        ctx.init(null, tm, null);
        sslSockFactory = ctx.getSocketFactory();
        return sslSockFactory;

    } catch (KeyStoreException | CertificateException | IOException | NoSuchAlgorithmException | KeyManagementException e) {
        throw new MqttSecurityException(e);
    }
}

这很有效但在20以下的Android API中没有成功。

this works perfectly but no success in Android APIs below 20.

推荐答案

终于找到了解决方案。

finally found a solution to this.

基于这个文档,Android API级别16(Android 4.1,Jelly Bean)支持TLS 1.1和TLS 1.2。 但默认情况下不启用,直到API等级为20+(Android 4.4用于手表,Kitkat Watch和Android 5.0 for phone,Lollipop)。

based on this documentation, TLS 1.1 and TLS 1.2 is supported from android API level 16 (Android 4.1, Jelly Bean). But it is'nt enabled by default until API level 20+ (Android 4.4 for watch, Kitkat Watch and Android 5.0 for phone, Lollipop).

所以我们需要的是在代码中以编程方式启用它们。我们该怎么做?这个问题有一个解决方案这里但它只是解决了你想要接受任何证书的问题。

so all we need is to enable them parogrammatically in code. how we gonna do this ? there is a solution for this problem here BUT it just resolves the problem for the case that you want to accept any certificate instead.

我们是什么需要做同样的事情,但我们自己签署的证书。所以我们就像下面这样做。第一部分就像我之前做的那样:( keyStoreInputStream 是.pfx文件的输入流)

what we need is do the same thing but with our own self signed certificate. so we do it like below. the first part is just like what i did before : (keyStoreInputStream is input stream of a .pfx file)

connection = createConnection(mqttCallback);

MqttConnectOptions connOpts = optionsFromModel(connectionModel);

connOpts.setSocketFactory(getSSLSocketFactory(keyStoreInputStream, keyStorePassword));

connection.addConnectionOptions(connOpts);

getSSLSocketFactory 方法更改为:

 public SSLSocketFactory getSSLSocketFactory (InputStream keyStore, String password) throws MqttSecurityException {
    try{

        SSLContext ctx = null;
        SSLSocketFactory sslSockFactory=null;

        KeyStore ks;
        ks = KeyStore.getInstance("PKCS12");
        ks.load(keyStore, password.toCharArray());

        TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509");
        tmf.init(ks);
        TrustManager[] tm = tmf.getTrustManagers();
        ctx = SSLContext.getInstance("TLS");
        ctx.init(null, tm, null);

        if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {
            sslSockFactory = new TLSSocketFactory(tm);
        } else {
            sslSockFactory = ctx.getSocketFactory();
        }
        return sslSockFactory;

    } catch (KeyStoreException | CertificateException | IOException | NoSuchAlgorithmException | KeyManagementException e) {
        throw new MqttSecurityException(e);
    }
}

TLSSocketFactory 类如下所示:

import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;


public class TLSSocketFactory extends SSLSocketFactory {

private SSLSocketFactory internalSSLSocketFactory;

public TLSSocketFactory(TrustManager[] trustManagers) throws KeyManagementException, NoSuchAlgorithmException {
    SSLContext context = SSLContext.getInstance("TLS");
    context.init(null, trustManagers, null);
    internalSSLSocketFactory = context.getSocketFactory();
}

@Override
public String[] getDefaultCipherSuites() {
    return internalSSLSocketFactory.getDefaultCipherSuites();
}

@Override
public String[] getSupportedCipherSuites() {
    return internalSSLSocketFactory.getSupportedCipherSuites();
}

@Override
public Socket createSocket() throws IOException {
    return enableTLSOnSocket(internalSSLSocketFactory.createSocket());
}

@Override
public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
    return enableTLSOnSocket(internalSSLSocketFactory.createSocket(s, host, port, autoClose));
}

@Override
public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
    return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port));
}

@Override
public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException {
    return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port, localHost, localPort));
}

@Override
public Socket createSocket(InetAddress host, int port) throws IOException {
    return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port));
}

@Override
public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
    return enableTLSOnSocket(internalSSLSocketFactory.createSocket(address, port, localAddress, localPort));
}

private Socket enableTLSOnSocket(Socket socket) {
    if(socket != null && (socket instanceof SSLSocket)) {
        ((SSLSocket)socket).setEnabledProtocols(new String[] {"TLSv1.2", "TLSv1.1"});
    }
    return socket;
}
}

这篇关于如何使用自签名证书连接到Android(paho客户端)中的Mqtt服务器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆