0

I'm trying to connect to a company server using HTTPS. The server certificates are stored on all clients (Windows) and I want to configure my Java app to use the Windows trust store.

I set javax.net.ssl.trustStoreType=Windows-ROOT which I understand should allow Java to use the certificates installed in Windows.

The Client is created in this method:

static CloseableHttpClient getClientWindowsTrust() throws Exception {
    System.setProperty("javax.net.ssl.trustStoreType", "Windows-ROOT");

    SSLContext sslContext = SSLContext.getDefault();

    DefaultClientTlsStrategy strat = new DefaultClientTlsStrategy(sslContext);
        
    var connectionManager = PoolingHttpClientConnectionManagerBuilder.create()
            .setTlsSocketStrategy(strat)
            .build();

    return HttpClients.custom()
            .setConnectionManager(connectionManager)
            .build();
}

The required certificates are in the Windows trust store and other apps (which I am assuming use these) are working ok.

The error message is:

TransportContext.java:363|Fatal (CERTIFICATE_UNKNOWN): PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

What might I be missing? How can I determine where exactly the path-building fails?

UPDATE

thanks to those who replied. I tried all suggestions but to no avail. I then focussed more on the server as I had tried everything I could think of on the client side.

The server recently got a new intermediate certificate and this is not being found by the client. I tried a different server which already has the new cert - and it worked. The difference is that server 1 is a Windows server with Apache and Tomcat, server 2 is a containerised server.

At the moment I'm guessing that the Windows installation has a config problem. I installed the new certificate on another Windows server that had been working and now it doesn't.

I'll post another update when I have more information.

PROBLEM SOLVED

It wasn't a client problem. The certificate was installed on the server by a co-worker who forgot to update the Apache config. The config still referenced the old intermediate cert and this caused the problem.

2
  • 4
    System properties are often only read when the class is loaded, thus setting them at run-time may have no effect. Therefore better set them via command-line to the Java runtime. At run-time the better way may be to load the Windows certificate store as KeyStore and then create a TrustManager and SSLContext from it. Commented Aug 25 at 15:32
  • 2
    Checking the JDK sources of TrustStoreManager it seems that the property javax.net.ssl.trustStoreType is checked every time a new instance is created. Commented Aug 26 at 9:09

1 Answer 1

1

I think you shall set it up on load

 public static void applyWindowsRootTrustStore() throws Exception {
        // 1. Load the Windows-ROOT keystore (system-wide trusted root CAs)
        //    Equivalent to trustStoreType=Windows-ROOT, trustStoreProvider=SunMSCAPI
        KeyStore windowsRoot = KeyStore.getInstance("Windows-ROOT", "SunMSCAPI");
        windowsRoot.load(null, null);
        //(Optionally also clear your system properties to set trustStore=NONE so that no file based trust store is looked up
        //    This ensures Java won't try to load a file-based truststore
        System.clearProperty("javax.net.ssl.trustStore");
        System.clearProperty("javax.net.ssl.trustStorePassword");
        System.setProperty("javax.net.ssl.trustStoreType", "Windows-ROOT");
        System.setProperty("javax.net.ssl.trustStoreProvider", "SunMSCAPI");

        // 2. Initialize a TrustManagerFactory with the Windows keystore
        TrustManagerFactory tmf =
                TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        tmf.init(windowsRoot);

        // 3. Create an SSLContext that uses only this TrustManager
        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(null, tmf.getTrustManagers(), null);

        // 4. Set this SSLContext as the default for all HTTPS connections
        SSLContext.setDefault(sslContext);
        HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());

    }

By setting javax.net.ssl.trustStore=NONE, you are explicitly telling Java “don’t even look for a file”.

Sign up to request clarification or add additional context in comments.

1 Comment

Why do you set the properties and manually load the Windows-ROOT keystore for constructing a SSLContext from it? If the properties work you don't need the SSLContext way.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.