我为mqtt客户机使用了以下代码-:运行在vmware中的mqtt代理基于证书的身份验证。我正在通过windows系统中的代码运行mqtt客户机。
public class TestClient {
public static void main(String[] args) {
String serverUrl = "ssl://192.168.5.12:8883";
String caFilePath = "rootca.pem";
String clientCrtFilePath = "Client.pem";
String clientKeyFilePath = "Client.key";
String mqttUserName = "guest";
String mqttPassword = "123123";
MqttClient client;
try {
client = new MqttClient(serverUrl, "2");
MqttConnectOptions options = new MqttConnectOptions();
// options.setUserName(mqttUserName);
// options.setPassword(mqttPassword.toCharArray());
// options.setSSLProperties(props);
options.setConnectionTimeout(0);
options.setKeepAliveInterval(300);
options.setMqttVersion(MqttConnectOptions.MQTT_VERSION_3_1);
SSLSocketFactory socketFactory = getSocketFactory(caFilePath,
clientCrtFilePath, clientKeyFilePath, "");
options.setSocketFactory(socketFactory);
System.out.println("starting connect the server...");
client.connect(options);
System.out.println("connected!");
Thread.sleep(1000);
client.subscribe(
"/u/56ca327d17531d08e76bddd4a215e37f5fd6082f7442151c4d3f1d100a0ffd4e",
0);
client.disconnect();
System.out.println("disconnected!");
} catch (MqttException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
private static SSLSocketFactory getSocketFactory(final String caCrtFile,
final String crtFile, final String keyFile, final String password)
throws Exception {
Security.addProvider(new BouncyCastleProvider());
// load CA certificate
X509Certificate caCert = null;
FileInputStream fis = new FileInputStream(caCrtFile);
BufferedInputStream bis = new BufferedInputStream(fis);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
while (bis.available() > 0) {
caCert = (X509Certificate) cf.generateCertificate(bis);
// System.out.println(caCert.toString());
}
// load client certificate
bis = new BufferedInputStream(new FileInputStream(crtFile));
X509Certificate cert = null;
while (bis.available() > 0) {
cert = (X509Certificate) cf.generateCertificate(bis);
// System.out.println(caCert.toString());
}
// load client private key
PEMParser pemParser = new PEMParser(new FileReader(keyFile));
Object object = pemParser.readObject();
PEMDecryptorProvider decProv = new JcePEMDecryptorProviderBuilder()
.build(password.toCharArray());
JcaPEMKeyConverter converter = new JcaPEMKeyConverter()
.setProvider("BC");
KeyPair key;
if (object instanceof PEMEncryptedKeyPair) {
System.out.println("Encrypted key - we will use provided password");
key = converter.getKeyPair(((PEMEncryptedKeyPair) object)
.decryptKeyPair(decProv));
} else {
System.out.println("Unencrypted key - no password needed");
key = converter.getKeyPair((PEMKeyPair) object);
}
pemParser.close();
// CA certificate is used to authenticate server
KeyStore caKs = KeyStore.getInstance(KeyStore.getDefaultType());
caKs.load(null, null);
caKs.setCertificateEntry("ca-certificate", caCert);
TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509");
tmf.init(caKs);
// client key and certificates are sent to server so it can authenticate
// us
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
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(KeyManagerFactory
.getDefaultAlgorithm());
kmf.init(ks, password.toCharArray());
// finally, create SSL socket factory
SSLContext context = SSLContext.getInstance("TLSv1.2");
context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
return context.getSocketFactory();
}
}
我得到下面的错误ip地址没有主题替代名称匹配
Unencrypted key - no password needed
starting connect the server...
MqttException (0) - javax.net.ssl.SSLHandshakeException: No subject alternative names matching IP address 192.168.5.12 found
我找了很多我没法修好请帮忙谢谢
2条答案
按热度按时间zzwlnbp81#
你有三个选择。
更改代理所呈现的证书时,它需要为ip地址包含san(使用者备用名称)条目。
更改您在客户端中使用的代理url,以使用代理的san或cn字段中已有的内容。
告诉你的应用程序不要验证远程代理证书。这是通过修改socketfactory代码来完成的,您必须包含一个自定义trustmanager,它不会检查主机名/ip是否与证书匹配。
选项1/2可能是最简单的(假设您创建了代理使用的证书),选项3是危险的,因为您不希望此代码滑出到生产环境中,因为它会使某些人更容易进行中间人攻击
wqlqzqxt2#
服务器证书的san字段中似乎缺少ip。如果在san字段中用ip重新创建服务器证书,它应该可以工作。有关类似的问题/答案及解释,请参见此处:的证书与任何主题替代名称都不匹配也许您可以从主机名(而不是ip)调用服务器,但主机名应作为san字段中的dns属性提供