How support multiple TrustStores in java SSL client application

后端 未结 2 967
醉话见心
醉话见心 2021-01-12 14:06

In our java application we need to communicate with a list of servers on SSL using https protocol. The list of servers to communicate will change at runtime. Initially we do

相关标签:
2条回答
  • 2021-01-12 14:10

    If you want to import certificate dynamically, you may need to use a custom x509TrustManager. This is done when configuring the SSLContext, which is itself used to create the SSLSocketFactory or SSLEngine.

    jSSLutils is a library that lets you wrap existing trust managers and customize certain settings. You don't need it, but it may help.

    This would go along these lines:

    PKIXSSLContextFactory sslContextFactory = new PKIXSSLContextFactory();
    sslContextFactory.setTrustManagerWrapper(new X509TrustManagerWrapper() {
        @Override
        public X509TrustManager wrapTrustManager(final X509TrustManager origManager) {
            return new X509TrustManager() { 
                @Override
                public X509Certificate[] getAcceptedIssuers() {
                    return origManager.getAcceptedIssuers();
                }
    
                @Override
                public void checkServerTrusted(X509Certificate[] chain,
                                                       String authType)
                        throws CertificateException {
                    try {
                        // This will call the default trust manager
                        // which will throw an exception if it doesn't know the certificate
                        origManager.checkServerTrusted(chain, authType);
                    } catch (CertificateException e) {
                        // If it throws an exception, check what this exception is
                        // the server certificate is in chain[0], you could
                        // implement a callback to the user to accept/refuse
                    }
                }
    
                @Override
                public void checkClientTrusted(X509Certificate[] chain,
                                                       String authType)
                        throws CertificateException {
                    origManager.checkClientTrusted(chain, authType);
                }
            };
        }
    });
    SSLContext sslContext = sslContextFactory.buildSSLContext();
    

    (The (PKIX)SSLContextFactory and X509TrustManagerWrapper come from jSSLutils, but the rest is available with the J2SE/J2EE.)

    There are a few CertificateExceptions that you may want to catch (see subclasses). If you make a callback to the user, it's possible that the SSL/TLS connection will fail the first time because of a time-out on the SSL/TLS handshake (if the callback takes too long to be replied to.)

    You could then use this SSLContext as your default using SSLContext.setSSLContext(...) (from Java 6), but that's not necessarily a good idea. If you can, pass the SSLContext to the library that makes the SSL/TLS connection. How this is done varies, but Apache HTTP Client 4.x, for example, has multiple options to configure its SSL settings, one of them being by passing KeyStores, another one being by passing an SSLContext.

    You could also to something per thread instead of per object that's going to connect (library dependent), by checking the current thread within the X509TrustManager: this would probably make things a bit more complex in terms of synchronization and thread management/"awareness" by the trust manager.

    0 讨论(0)
  • 2021-01-12 14:16

    This question is so old that I have my doubts my bit will help anyone but here goes...

    If you want to solve the OP's (original poster) problem without resorting to code changes you can configure your JVM (I only tested with Tomcat) to support the OP's desired config:

    1. leave the 'packaged' JDK cacerts file alone
    2. import your certs into a separate file and have your JAVA apps 'trust' them

    I used to just import my additional cert into a separate file and then reference it in my JVM startup with the parameter -Djavax.net.ssl.trustStore=$JAVA_HOME/jre/lib/security/jssecacerts with great success but I guess the recent (somewhat) JAVA security problems changed an automated inclusion of the cacerts file distributed with the SDK.

    So I found a nifty solution using intel from this post and the these pages (with some minor changes):

    • http://www.coderanch.com/t/529157/Tomcat/Configure-Tomcat-trust-store-cacerts
    • http://andyarismendi.blogspot.com/2012/01/changing-tomcats-ca-trust-keystore-file.html

    What I used to do:

    • set the JVM trustStore parameter to my separate keystore file (that I'd import additional certs into) as follows

    What I do Now:

    • Set the trustStore parameter to the 'packaged' cacerts file
    • Set the keyStore parameter to my 'additional certs' file
    • Set the keyStorePassword parameter to my keyStore's password (default is changeit)

    What it looks like:

    -Djavax.net.ssl.trustStore=$JAVA_HOME/jre/lib/security/cacerts \
    -Djavax.net.ssl.keyStore=$JAVA_HOME/jre/lib/security/jssecacerts \
    -Djavax.net.ssl.keyStorePassword="changeit" \
    

    Hope this is helpful to someone. I'm not 100% that you need to specify the keyStore password since you don't with the trustStore, but it works when you do.

    0 讨论(0)
提交回复
热议问题