gpt4 book ai didi

java - 从 Java 客户端 (Eclipse Paho)​​ 到 mosquitto 代理 : "unknown_ca" 的 SSL 连接

转载 作者:塔克拉玛干 更新时间:2023-11-03 05:02:59 25 4
gpt4 key购买 nike

我们正在研究 Android 的推送通知平台(Google 的 C2DM 的故障转移)我正在使用 Eclipse Paho Java 客户端连接到 mosquitto 代理 (1.0.3)。代理安装在 Ubuntu 12.04(AWS EC2 实例)上我使用非加密的 TCP 连接成功地将客户端连接到服务器。顺便说一句,在调整内核参数后,我能够在一台中型 EC2 机器上为一个代理实例打开 100K 个并发客户端。干得好,蚊子!

现在我正在尝试使用 SSL 建立安全连接。我想使用客户端证书对客户端进行身份验证。我遵循了 mosquito_tls page 中的解释并为服务器和客户端生成 key 和自签名证书。配置服务器以使用 SSL。

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

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

  1. 使用bouncy caSTLe加载上述三个文件。
  2. 将 CA 证书放入 keystore 并使用它创建 TrustManagerFactory。
  3. 将客户端 key 和证书放在另一个 keystore 中,并用它来创建一个KeyManagerFactory。
  4. 创建了一个 SSLContext 并使用两个工厂对其进行了初始化。
  5. 从 SSLContext 创建一个 SSLSocketFactory 并将其传递给 Paho 的 MqttConnectOptions

当我进行连接时,我从 mosquitto 收到以下错误

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

mosquito.conf 看起来像这样

# 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

最佳答案

好的,在 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();
}

关于java - 从 Java 客户端 (Eclipse Paho)​​ 到 mosquitto 代理 : "unknown_ca" 的 SSL 连接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12997559/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com