【问题标题】:How to use a self signed certificate to connect to a Mqtt server in Android (paho client)?如何使用自签名证书连接到 Android(paho 客户端)中的 Mqtt 服务器?
【发布时间】:2018-05-04 18:35:22
【问题描述】:

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

到目前为止我做了什么:

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

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

3- 使用以下代码加载自签名证书:

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);
        sslSockFactory = ctx.getSocketFactory();
        return sslSockFactory;

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

这可以完美运行,但在低于 20 的 Android API 中没有成功。

【问题讨论】:

    标签: java android ssl mqtt paho


    【解决方案1】:

    终于找到了解决办法。

    基于 this 文档,从 android API 级别 16(Android 4.1,Jelly Bean)开始支持 TLS 1.1 和 TLS 1.2。 但默认情况下不会启用,直到 API 级别 20+(Android 4.4 for watch、Kitkat Watch 和 Android 5.0 for phone、Lollipop)。

    所以我们只需要在代码中以语法方式启用它们。我们要怎么做?这个问题有一个解决方案here 但它只是解决了您想要接受任何证书的情况。

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

    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;
    }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-08-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-09-19
      • 1970-01-01
      相关资源
      最近更新 更多