当前位置: 首页 > 知识库问答 >
问题:

从Java客户机(Eclipse Paho)到mosquitto代理的SSL连接:“未知_ca”

戈曾琪
2023-03-14

我们正在研究Android推送通知平台(谷歌C2DM的故障切换),我正在使用Eclipse Paho Java客户端连接到Mosquito broker(1.0.3)。代理安装在Ubuntu12.04(AWS EC2实例)上。我使用未加密的TCP连接成功地将客户端连接到服务器。顺便说一句,在调整了内核参数之后,我能够在一台中型EC2机器上为一个代理实例打开10万个并发客户端。干得好,莫斯奎托!

现在我正在尝试使用SSL建立安全连接。我想使用客户端证书对客户端进行身份验证。我按照tls页面中的解释,为服务器和客户端生成密钥和自签名证书。将服务器配置为使用SSL。

对于客户端部分,我查看了Mosquito_tls_集的签名,并注意到它需要CA证书、客户端密钥和证书文件。我认为CA证书用于客户端对服务器进行身份验证,而客户端密钥和证书用于服务器对客户端进行身份验证。我说得对吗?

下面是我在Java方面所做的:

  1. 使用bouncy castle加载上述三个文件

当我做连接,我得到以下错误从蚊子

OpenSSL Error: error:140890B2:SSL routines:SSL3_GET_CLIENT_CERTIFICATE:no certificate returned
Socket read error on client (null), disconnecting.

编辑:现在我在客户端看到以下异常

javax.net.ssl.SSLHandshakeException: Received fatal alert: unknown_ca

这是完整的密码

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

    PEMReader reader = new PEMReader(new InputStreamReader(new ByteArrayInputStream(Files.readAllBytes(Paths.get(caCrtFile)))));
    X509Certificate caCert = (X509Certificate)reader.readObject();
    reader.close();

    reader = new PEMReader(new InputStreamReader(new ByteArrayInputStream(Files.readAllBytes(Paths.get(crtFile)))));
    X509Certificate cert = (X509Certificate)reader.readObject();
    reader.close();

    reader = new PEMReader(
            new InputStreamReader(new ByteArrayInputStream(Files.readAllBytes(Paths.get(keyFile)))),
            new PasswordFinder() {
                public char[] getPassword() {
                    return password.toCharArray();
                }
            }
    );
    KeyPair key = (KeyPair)reader.readObject();
    reader.close();

    KeyStore caKs = KeyStore.getInstance("JKS");
    caKs.load(null, null);
    caKs.setCertificateEntry("ca-certificate", caCert);
    TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");
    tmf.init(caKs);

    KeyStore ks = KeyStore.getInstance("JKS");
    ks.load(null, null);
    ks.setCertificateEntry("certificate", cert);
    ks.setKeyEntry("private-key", key.getPrivate(), password.toCharArray(), new java.security.cert.Certificate[]{cert});
    //ks.setKeyEntry("public-key", key.getPublic(), password.toCharArray(), new java.security.cert.Certificate[]{cert});
    KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
    kmf.init(ks, password.toCharArray());

    SSLContext context = SSLContext.getInstance("SSLv3");
    context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);

    return context.getSocketFactory();
}

蚊子。看起来像这样

# general options
pid_file /home/ubuntu/mosquitto.pid

# persistence
queue_qos0_messages false
persistence false

# logging
log_dest stdout
connection_messages true
log_timestamp false

# default listener
# disable default listener (open only SSL listener)
#port 1883
#max_connections -1

# SSL listener
listener 1883
cafile /home/ubuntu/etc/ca.crt
certfile /home/ubuntu/etc/server.crt
keyfile /home/ubuntu/etc/server.key
require_certificate true
use_identity_as_username true
max_connections -1

共有1个答案

戚鸿
2023-03-14

好的,在mosquitto开发者(thx,Roger Light)的支持下,我们解决了这个问题。生成证书时提供的详细信息(公司、组织单位、通用名称)在CA、客户端和服务器证书中必须不同。否则,代码会进行一些小的更改。为了清晰起见,我在这里重新发布了正确的代码和一些注释:

import java.io.*;
import java.nio.file.*;
import java.security.*;
import java.security.cert.*;
import java.security.interfaces.*;
import javax.net.ssl.*;

import org.bouncycastle.jce.provider.*;
import org.bouncycastle.openssl.*;

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

    // load CA certificate
    PEMReader reader = new PEMReader(new InputStreamReader(new ByteArrayInputStream(Files.readAllBytes(Paths.get(caCrtFile)))));
    X509Certificate caCert = (X509Certificate)reader.readObject();
    reader.close();

    // load client certificate
    reader = new PEMReader(new InputStreamReader(new ByteArrayInputStream(Files.readAllBytes(Paths.get(crtFile)))));
    X509Certificate cert = (X509Certificate)reader.readObject();
    reader.close();

    // load client private key
    reader = new PEMReader(
            new InputStreamReader(new ByteArrayInputStream(Files.readAllBytes(Paths.get(keyFile)))),
            new PasswordFinder() {
                public char[] getPassword() {
                    return password.toCharArray();
                }
            }
    );
    KeyPair key = (KeyPair)reader.readObject();
    reader.close();

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

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

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

    return context.getSocketFactory();
}
 类似资料:
  • 由于SSL配置错误,队列管理器jmsdemo无法用于客户端连接。 (AMQ4199)由于SSL 配置错误,队列管理器jmsdemo无法用于客户端连接。(AMQ4199)严重程度:30(严重错误)说明:用户正试图使用安全连接连接到远程队列管理器。响应:检查目标队列管理器和本地SSL信任存储区的SSL配置。 b)以下错误信息提取为“AMQERR01”错误文件(来自服务器端) 谢谢JK

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

  • 我对javax有问题。websocket(使用Eclipse IDE和Jetty 9服务器)。我写了ClientEndDoint(带有所有注释)。这段代码可以与“ws://”配合使用,但我在尝试使用“wss://”时遇到了问题。 我试图做它与SSLContext,但不知道如何我可以添加SSLContextFactory到我的会话或套接字容器。 或者我如何可以使所有连接可信? StackTrace:

  • 下面是我的服务器代码: 下面是我的客户端活动代码: 以下是客户端活动的xml布局文件: 因此,我开始认为这不是连接端口的问题,而是应用程序的android客户端的问题。但我想不出有什么问题。 顺便说一下,当我试图发送消息时,运行客户端的手机和运行服务器的笔记本电脑都连接到了同一个网络。

  • jdbc:mysql://x.x.x.x:3306/xxxdb?VerifyServerCertificate=true&usessl=true&requiressl=true+user+password Mon Nov 14 17:23:53 S>2016警告:不建议在没有服务器身份验证的情况下建立SSL连接。根据MySQL 5.5.45+、5.6.26+和5.7.6+的要求,如果未设置显式选项

  • 这里的AWS文档([http://docs.AWS.amazon.com/iot/latest/developerguide/iot-message-broker.html])是这样说的:- “message broker维护所有客户端会话和每个会话订阅的列表。在主题上发布消息时,代理检查订阅映射到该主题的会话。然后代理将发布消息转发给所有当前有连接客户端的会话。对于所有没有连接客户端的匹配会话,