Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to fix "javax.net.ssl.SSLHandshakeException: TLS Server certificate issued after 2019-04-16 and anchored by a distrusted legacy Symantec root CA"

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

like image 639
Joschua Haß Avatar asked Oct 17 '19 17:10

Joschua Haß


1 Answers

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.

like image 121
Jim Avatar answered Nov 19 '22 15:11

Jim