在 Mosquitto MQTT SSL/TLS 实例和客户端 java 应用程序中使用 DigiCert 全球根 CA
Using DigiCert Global Root CA in a Mosquitto MQTT SSL/TLS instance and client java application
我是 运行 用于 TLS1.2 的 Mosquitto MQTT 成功使用从 OpenSSL
生成的证书并在 mosquitto 配置文件中使用。这也涉及到Java客户端手动指定连接mosquitto的CA证书文件
我想使用 Java 密钥库中的 DigiCert Global Root CA
。
当前设置
此 Mosquitto 配置文件如下所示:
cafile .\m2mqtt_ca.crt
# PEM encoded server certificate.
certfile .\m2mqtt_srv.crt
# PEM encoded keyfile.
keyfile .\m2mqtt_srv.key
tls_version tlsv1.2
这些证书是使用 OpenSSL 使用以下命令生成的:
# generate key
openssl genrsa -des3 -out m2mqtt_ca.key 2048
# create CA certificate
openssl req -new -x509 -days 3650 -key m2mqtt_ca.key -out m2mqtt_ca.crt
# create private key for the server
openssl genrsa -out m2mqtt_srv.key 2048
# create certificate request from CA
openssl req -new -out m2mqtt_srv.csr -key m2mqtt_srv.key
# verify and sign the certificate request
openssl x509 -req -in m2mqtt_srv.csr -CA m2mqtt_ca.crt -CAkey m2mqtt_ca.key -CAcreateserial -out m2mqtt_srv.crt -days 3650
它可以在客户端 java 应用程序中使用,使用以下内容:
package acme.messaging;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.PEMParser;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManagerFactory;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.KeyStore;
import java.security.Security;
public class SslUtil {
public static final SSLSocketFactory Instance;
static {
Instance = SslUtil.getSocketFactory(
"N:\work\acme\mqtt-ssl\messaging\mqtt\certs\m2mqtt_ca.crt");
}
private static X509CertificateHolder loadCACert(String caCrtFile) throws IOException {
PEMParser reader =
new PEMParser(
new InputStreamReader(new ByteArrayInputStream(
Files.readAllBytes(Paths.get(caCrtFile)))));
X509CertificateHolder caCert = (X509CertificateHolder) reader.readObject();
reader.close();
return caCert;
}
static SSLSocketFactory getSocketFactory(
final String caCrtFile) {
try {
Security.addProvider(new BouncyCastleProvider());
JcaX509CertificateConverter jcaX509CertificateConverter = new JcaX509CertificateConverter();
X509CertificateHolder caCertificateHolder = loadCACert(caCrtFile);
// CA certificate is used to authenticate server
KeyStore caKs = KeyStore.getInstance(KeyStore.getDefaultType());
caKs.load(null, null);
caKs.setCertificateEntry("ca-certificate", jcaX509CertificateConverter.getCertificate(caCertificateHolder));
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(caKs);
// finally, create SSL socket factory
SSLContext context = SSLContext.getInstance("TLSv1.2");
context.init(null, tmf.getTrustManagers(), null);
return context.getSocketFactory();
} catch (Exception ex) {
return null;
}
}
}
// consume
String uri = "ssl://localhost:1884";
String clientId = "1002";
final MqttMessage mqttMessage = new MqttMessage();
String messageText = "Some data";
mqttMessage.setPayload(messageText.getBytes());
try (MqttClient client = new MqttClient(uri, clientId)) {
if (!client.isConnected()) {
final MqttConnectOptions options = new MqttConnectOptions();
options.setUserName("acme-user");
options.setPassword("acme-user".toCharArray());
options.setSocketFactory(SslUtil.Instance);
client.connect(options);
}
mqttMessage.setRetained(true);
client.publish("test/writeme", mqttMessage);
}
问题
是否可以在 Mosquitto 中使用基于 DigiCert Global Root CA
的证书?
目前它存在于我的 Java 密钥库中:
可以导出,但不确定是否可以在OpenSSL工作流中正确使用。我已尝试在上述步骤中使用它,但这会产生错误。想法是生成相同的文件并将它们导入到蚊子配置中。
尝试通过 OpenSSL 重用 DigiCert 证书时出错
这里我确实尝试使用生成的文件和从 DigiCert
下载的文件
以下命令行生成于DigiCert website
openssl req -new -newkey rsa:2048 -nodes -out localhost.csr -keyout localhost.key -subj "/C=GB/ST=Durham/L=Durham/O=quorum/CN=localhost"
Can't load ./.rnd into RNG
8016:error:2406F079:random number generator:RAND_load_file:Cannot open file:crypto\rand\randfile.c:88:Filename=./.rnd
Generating a RSA private key
......................................................................................................................................................................+++++
.....................................................................................................+++++
writing new private key to 'localhost.key'
注意:我不知道这里的事件顺序。
然后是这些:
openssl x509 -req -in localhost.csr -CA DigiCertAssuredIDRootCA.crt -CAkey localhost.key -CAcreateserial -out m2mqtt_srv.crt -days 3650
错误:
Signature ok
subject=C = GB, ST = Durham, L = Durham, O = quorum, CN = localhost
unable to load certificate
9896:error:0909006C:PEM routines:get_name:no start line:crypto\pem\pem_lib.c:745:Expecting: TRUSTED CERTIFICATE
也试过这个:
openssl x509 -req -in localhost.csr -CA DigiCertAssuredIDRootCA.crt -CAkey DigiCertAssuredIDRootCA.crt.pem -CAcreateserial -out m2mqtt_srv.crt -days 3650
错误:
Signature ok
subject=C = GB, ST = Durham, L = Durham, O = quorum, CN = localhost
unable to load certificate
12904:error:0909006C:PEM routines:get_name:no start line:crypto\pem\pem_lib.c:745:Expecting: TRUSTED CERTIFICATE
如评论中所述。
您不能将证书签署为受信任的 CA(如果可以,您为什么要信任 CA?)。
您必须生成 CSR(证书签名请求)并将其发送给 CA 以供他们签名(通常会向您收费)。他们还将证明您拥有证书所代表的域。 (LetsEncrypt 使用 certbot 工具为您完成这一切,并将免费完成)。
此外,任何受信任的 CA 都不会为 localhost
签署证书。
我是 运行 用于 TLS1.2 的 Mosquitto MQTT 成功使用从 OpenSSL
生成的证书并在 mosquitto 配置文件中使用。这也涉及到Java客户端手动指定连接mosquitto的CA证书文件
我想使用 Java 密钥库中的 DigiCert Global Root CA
。
当前设置
此 Mosquitto 配置文件如下所示:
cafile .\m2mqtt_ca.crt
# PEM encoded server certificate.
certfile .\m2mqtt_srv.crt
# PEM encoded keyfile.
keyfile .\m2mqtt_srv.key
tls_version tlsv1.2
这些证书是使用 OpenSSL 使用以下命令生成的:
# generate key
openssl genrsa -des3 -out m2mqtt_ca.key 2048
# create CA certificate
openssl req -new -x509 -days 3650 -key m2mqtt_ca.key -out m2mqtt_ca.crt
# create private key for the server
openssl genrsa -out m2mqtt_srv.key 2048
# create certificate request from CA
openssl req -new -out m2mqtt_srv.csr -key m2mqtt_srv.key
# verify and sign the certificate request
openssl x509 -req -in m2mqtt_srv.csr -CA m2mqtt_ca.crt -CAkey m2mqtt_ca.key -CAcreateserial -out m2mqtt_srv.crt -days 3650
它可以在客户端 java 应用程序中使用,使用以下内容:
package acme.messaging;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.PEMParser;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManagerFactory;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.KeyStore;
import java.security.Security;
public class SslUtil {
public static final SSLSocketFactory Instance;
static {
Instance = SslUtil.getSocketFactory(
"N:\work\acme\mqtt-ssl\messaging\mqtt\certs\m2mqtt_ca.crt");
}
private static X509CertificateHolder loadCACert(String caCrtFile) throws IOException {
PEMParser reader =
new PEMParser(
new InputStreamReader(new ByteArrayInputStream(
Files.readAllBytes(Paths.get(caCrtFile)))));
X509CertificateHolder caCert = (X509CertificateHolder) reader.readObject();
reader.close();
return caCert;
}
static SSLSocketFactory getSocketFactory(
final String caCrtFile) {
try {
Security.addProvider(new BouncyCastleProvider());
JcaX509CertificateConverter jcaX509CertificateConverter = new JcaX509CertificateConverter();
X509CertificateHolder caCertificateHolder = loadCACert(caCrtFile);
// CA certificate is used to authenticate server
KeyStore caKs = KeyStore.getInstance(KeyStore.getDefaultType());
caKs.load(null, null);
caKs.setCertificateEntry("ca-certificate", jcaX509CertificateConverter.getCertificate(caCertificateHolder));
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(caKs);
// finally, create SSL socket factory
SSLContext context = SSLContext.getInstance("TLSv1.2");
context.init(null, tmf.getTrustManagers(), null);
return context.getSocketFactory();
} catch (Exception ex) {
return null;
}
}
}
// consume
String uri = "ssl://localhost:1884";
String clientId = "1002";
final MqttMessage mqttMessage = new MqttMessage();
String messageText = "Some data";
mqttMessage.setPayload(messageText.getBytes());
try (MqttClient client = new MqttClient(uri, clientId)) {
if (!client.isConnected()) {
final MqttConnectOptions options = new MqttConnectOptions();
options.setUserName("acme-user");
options.setPassword("acme-user".toCharArray());
options.setSocketFactory(SslUtil.Instance);
client.connect(options);
}
mqttMessage.setRetained(true);
client.publish("test/writeme", mqttMessage);
}
问题
是否可以在 Mosquitto 中使用基于 DigiCert Global Root CA
的证书?
目前它存在于我的 Java 密钥库中:
可以导出,但不确定是否可以在OpenSSL工作流中正确使用。我已尝试在上述步骤中使用它,但这会产生错误。想法是生成相同的文件并将它们导入到蚊子配置中。
尝试通过 OpenSSL 重用 DigiCert 证书时出错
这里我确实尝试使用生成的文件和从 DigiCert
下载的文件以下命令行生成于DigiCert website
openssl req -new -newkey rsa:2048 -nodes -out localhost.csr -keyout localhost.key -subj "/C=GB/ST=Durham/L=Durham/O=quorum/CN=localhost"
Can't load ./.rnd into RNG
8016:error:2406F079:random number generator:RAND_load_file:Cannot open file:crypto\rand\randfile.c:88:Filename=./.rnd
Generating a RSA private key
......................................................................................................................................................................+++++
.....................................................................................................+++++
writing new private key to 'localhost.key'
注意:我不知道这里的事件顺序。
然后是这些:
openssl x509 -req -in localhost.csr -CA DigiCertAssuredIDRootCA.crt -CAkey localhost.key -CAcreateserial -out m2mqtt_srv.crt -days 3650
错误:
Signature ok
subject=C = GB, ST = Durham, L = Durham, O = quorum, CN = localhost
unable to load certificate
9896:error:0909006C:PEM routines:get_name:no start line:crypto\pem\pem_lib.c:745:Expecting: TRUSTED CERTIFICATE
也试过这个:
openssl x509 -req -in localhost.csr -CA DigiCertAssuredIDRootCA.crt -CAkey DigiCertAssuredIDRootCA.crt.pem -CAcreateserial -out m2mqtt_srv.crt -days 3650
错误:
Signature ok
subject=C = GB, ST = Durham, L = Durham, O = quorum, CN = localhost
unable to load certificate
12904:error:0909006C:PEM routines:get_name:no start line:crypto\pem\pem_lib.c:745:Expecting: TRUSTED CERTIFICATE
如评论中所述。
您不能将证书签署为受信任的 CA(如果可以,您为什么要信任 CA?)。
您必须生成 CSR(证书签名请求)并将其发送给 CA 以供他们签名(通常会向您收费)。他们还将证明您拥有证书所代表的域。 (LetsEncrypt 使用 certbot 工具为您完成这一切,并将免费完成)。
此外,任何受信任的 CA 都不会为 localhost
签署证书。