java如何修复“javax.net.ssl.SSLHandshakeException:20190416之后颁发并由不受信任的旧Symantec根CA锚定的TLS服务器证书”
我在使用Java和自签名证书连接到MQTT服务器时遇到以下异常。我使用了VeriSign Class 3-Public-Primary-Certification-Authority-G5。佩姆作为卡塞特。佩姆
代码是针对Linux服务器的,但目前我正在IntelliJ IDEA上编程
public class TestMQTT {
public static void main(String[] args) {
String serverUrl = "ssl://A35IXNRWYOLJWQ.iot.eu-central-1.amazonaws.com:8883";
String caFilePath = "H:/Users/Joschua/IdeaProjects/ServerMain/src/de/AirConnect/SSL/cacert.pem";
String clientCrtFilePath = "H:/Users/Joschua/IdeaProjects/ServerMain/src/de/AirConnect/SSL/Certificate.cer";
String clientKeyFilePath = "H:/Users/Joschua/IdeaProjects/ServerMain/src/de/AirConnect/SSL/client.key"; //privat key
MqttClient client;
try {
client = new MqttClient(serverUrl, "anyID");
MqttConnectOptions options = new MqttConnectOptions();
options.setConnectionTimeout(60);
options.setKeepAliveInterval(60);
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!");
.......
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();
}
}
输出为:
MqttException (0) - javax.net.ssl.SSLHandshakeException: TLS Server certificate issued after 2019-04-16 and anchored by a distrusted legacy Symantec root CA: CN=VeriSign Class 3 Public Primary Certification Authority - G5, OU="(c) 2006 VeriSign, Inc. - For authorized use only", OU=VeriSign Trust Network, O="VeriSign, Inc.", C=US
at org.eclipse.paho.client.mqttv3.internal.ExceptionHelper.createMqttException(ExceptionHelper.java:38)
at org.eclipse.paho.client.mqttv3.internal.ClientComms$ConnectBG.run(ClientComms.java:736)
at java.base/java.lang.Thread.run(Thread.java:835)
Caused by: javax.net.ssl.SSLHandshakeException: TLS Server certificate issued after 2019-04-16 and anchored by a distrusted legacy Symantec root CA: CN=VeriSign Class 3 Public Primary Certification Authority - G5, OU="(c) 2006 VeriSign, Inc. - For authorized use only", OU=VeriSign Trust Network, O="VeriSign, Inc.", C=US
at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:131)
at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:320)
at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:263)
at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:258)
at java.base/sun.security.ssl.CertificateMessage$T12CertificateConsumer.checkServerCerts(CertificateMessage.java:641)
at java.base/sun.security.ssl.CertificateMessage$T12CertificateConsumer.onCertificate(CertificateMessage.java:460)
at java.base/sun.security.ssl.CertificateMessage$T12CertificateConsumer.consume(CertificateMessage.java:360)
at java.base/sun.security.ssl.SSLHandshake.consume(SSLHandshake.java:392)
at java.base/sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:441)
at java.base/sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:419)
at java.base/sun.security.ssl.TransportContext.dispatch(TransportContext.java:177)
at java.base/sun.security.ssl.SSLTransport.decode(SSLTransport.java:164)
at java.base/sun.security.ssl.SSLSocketImpl.decode(SSLSocketImpl.java:1180)
at java.base/sun.security.ssl.SSLSocketImpl.readHandshakeRecord(SSLSocketImpl.java:1091)
at java.base/sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:402)
at org.eclipse.paho.client.mqttv3.internal.SSLNetworkModule.start(SSLNetworkModule.java:149)
at org.eclipse.paho.client.mqttv3.internal.ClientComms$ConnectBG.run(ClientComms.java:722)
... 1 more
Caused by: sun.security.validator.ValidatorException: TLS Server certificate issued after 2019-04-16 and anchored by a distrusted legacy Symantec root CA: CN=VeriSign Class 3 Public Primary Certification Authority - G5, OU="(c) 2006 VeriSign, Inc. - For authorized use only", OU=VeriSign Trust Network, O="VeriSign, Inc.", C=US
at java.base/sun.security.validator.SymantecTLSPolicy.checkNotBefore(SymantecTLSPolicy.java:189)
at java.base/sun.security.validator.SymantecTLSPolicy.checkDistrust(SymantecTLSPolicy.java:172)
at java.base/sun.security.validator.CADistrustPolicy$1.checkDistrust(CADistrustPolicy.java:54)
at java.base/sun.security.validator.EndEntityChecker.check(EndEntityChecker.java:167)
at java.base/sun.security.validator.Validator.validate(Validator.java:277)
at java.base/sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:321)
at java.base/sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:221)
at java.base/sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:129)
at java.base/sun.security.ssl.CertificateMessage$T12CertificateConsumer.checkServerCerts(CertificateMessage.java:625)
... 13 more
我尝试使用MQTT连接到服务器。fx(Windows程序)和它的工作
希望你能帮助我。 乔斯丘,你好
# 1 楼答案
适用于Linux
我可以通过注释掉
java.security
文件中的jdk.security.caDistrustPolicies=SYMANTEC_TLS
行来解决这个问题。 在我的例子中,这个文件位于/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.232.b09-0.el7_7.x86_64/jre/lib/security/java.security
您应该能够使用以下命令
alternatives config java
在您的环境中找到它注1:赛门铁克证书不受信任是有原因的,信任它的风险由您自己承担
注意2:如果使用Gradle进行构建,则需要先杀死Gradle守护进程,否则Gradle仍使用旧的jvm安全配置
# 2 楼答案
适用于Windows(OpenJDK)
我能找到java。在C:\Program Files\RedHat\java-11-openjdk-11.0.7-1\lib\security下有一个安全文件,但我在该文件中找不到CaDistrustPolicys
经过长时间的寻找,我终于找到了有效的解决办法
这是我在下面一行注释并重新启动VS代码的文件,它工作得很好