当前位置: 首页 > 面试题库 >

如何使用自签名证书连接到Android(Paho客户端)中的Mqtt服务器?

席俊达
2023-03-14
问题内容

我在使用自签名证书连接到mqtt服务器时遇到问题。即时通讯使用Paho客户端,并想使用连接到html" target="_blank">服务器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中无法成功。


问题答案:

终于找到了解决办法。

根据此文档,Android API级别16(Android 4.1,Jelly
Bean)支持TLS 1.1和TLS 1.2。 但默认情况下, 直到API级别20+才 启用 (手表使用Android 4.4,Kitkat
Watch和手机5.0,Lollipop Android 5.0)。

因此,我们需要的是在代码中以图形方式启用它们。我们该怎么做?这里有解决此问题的方法,但是它只是解决了您要接受任何证书的情况下的问题。

我们需要做的是做同样的事情,但要使用我们自己的自签名证书。所以我们像下面这样
第一部分就像我之前所做的那样:(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;
}
}


 类似资料:
  • 问题内容: 我完全被困在这里。我有一个Java客户端代码,需要使用自签名证书连接到SSL服务器。 仅 当我在服务器端禁用SSLv2支持时, 才会 出现此问题。 痕迹是 在服务器端,我可以看到以下跟踪: 如果启用SSL2,我会看到 而且一切正常。 我还知道那不是服务器端的东西,因为与其他软件连接可以正常工作。 知道我在做什么错吗? 还有人知道这个“读取客户端问候A / B”是什么意思吗? 谢谢 更新

  • 我的Mosquitto实例没有设置身份验证或密码。我尝试在Mosquitto日志中打开调试消息,但它们没有显示任何有用的信息。我不知所措。为什么我无法从C++Paho代码连接到Mosquitto? 编辑:这是客户端代码...同样,这对Adafruit很有效,但是当我把它指向我在localhost的蚊子时,它会像描述的那样挂起。(我省略了用户名和密码--我正在发送它们,但我真的不认为这些是问题所在,

  • websocket客户端(使用Autobahn/Python和Twisted)需要连接到websocket服务器:客户端需要向服务器提供其客户端证书,客户端需要检查服务器的证书。例如,这些证书是在Kubernetes minikube安装过程中创建的。特别地: 服务器证书(据我所知为X509格式) 客户端证书~/。minikube/客户。按键 我已经检查过,我可以成功地使用这些证书密钥使用发出库伯

  • 问题内容: 它看起来像一个标准问题,但是我在任何地方都找不到清晰的方向。 我有Java代码试图连接到可能带有自签名(或过期)证书的服务器。该代码报告以下错误: 据我了解,我必须使用keytool并告诉java允许这种连接是可以的。 解决此问题的所有说明均假定我完全精通keytool,例如 生成服务器的私钥并将其导入密钥库 是否有人可以发布详细说明? 我正在运行Unix,所以bash脚本是最好的。

  • 问题内容: 我正在编写django应用程序,该应用程序应充当MQTT发布者和订阅者。 我应该在哪里启动Paho客户端并运行loop_forever()函数。 应该在wsgi.py中吗? 问题答案: 更新: 如果您需要在Django的多个线程运行,那么发布您的Django应用程序的信息,您可以使用辅助功能从发布泛美卫生组织的模块- https://eclipse.org/paho/clients/p

  • 我需要创建web服务客户端,这家提供服务的公司向我们发送wsdl文件。我有wsdl文件、用户名和密码、服务url和txt文件,其中包含一些密钥,比如“20A9 38 4e 82 3a 94 d1…”。服务器有自签名证书,我试图通过InstallCert获取证书。java,使用keytool等生成密钥库。当我使用axis2 wsdl2java从wsdl生成客户端时,它会生成客户端,但在生成过程结束时