I got the exception below while connecting to a MQTT Server with Java and self signed certificates. I used VeriSign-Class 3-Public-Primary-Certification-Authority-G5.pem as cacert.pem.
The code is for an Linux server but currently I’m programming it on 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(); } }
The output is:
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
I tried to connect to the server with MQTT.fx (Windows program) and it worked.
Hope you can help me. Greetings Joschua
Advertisement
Answer
For Linux
I am able to resolve this issue by comment out the line jdk.security.caDistrustPolicies=SYMANTEC_TLS
in java.security
file.
In my case, this file is located in /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.232.b09-0.el7_7.x86_64/jre/lib/security/java.security
You should be able to find it in your environment by using the following command alternatives --config java
Note 1 : The Symantec cert was distrusted for a reason and trust it at your own risk.
Note 2 : If you are using Gradle to build, you need to kill the gradle daemon first, otherwise gradle still use old jvm security configuration.