truststore in jar?

Discussion in 'Java' started by Tim Ward, May 24, 2006.

  1. Tim Ward

    Tim Ward Guest

    Scenario: Java application distributed as a single jar file. It now needs to
    make SSL connections where it used to make TCP connections. So it needs a
    truststore so as to be able to validate the certificate presented by the
    server.

    I've got all that working fine with the truststore in a separate disk file,
    but that's no use for distributing the application. So, if I include the
    truststore in the jar file (along with the images and other resource files)
    how do I make the Java SSL system use it?

    (The only suggestion I've found is to include it as a resource, then write
    some code to copy this to a disk file before setting the system property.
    This is nonsense, mostly because it is obviously utterly silly but also
    because it's less than obvious that you can guarantee to find somewhere to
    put the file safely and reliably.)

    --
    Tim Ward
    Brett Ward Limited - www.brettward.co.uk
     
    Tim Ward, May 24, 2006
    #1
    1. Advertising

  2. Tim Ward

    EJP Guest

    Tim Ward wrote:
    >
    > So, if I include the
    > truststore in the jar file (along with the images and other resource files)
    > how do I make the Java SSL system use it?


    You can do it by getting a javax.net.ssl.SSLContext via
    SSLContext.getInstance, then call SSLContext.init(). The second
    parameter is an array of TrustManagers. You can define your own
    TrustManager to load your truststore from wherever you like, using in
    your case java.security.KeyStore.load() from your truststore resource's
    input stream, and implement the X509TrustManager API to respond
    appropriately when SSL asks you any of those questions by looking in
    that KeyStore. You then use that SSLContext to obtain your SSL socket
    factories, use them to get your SSLSockets, and away you go.

    However having said all that I would probably recommend that you rethink
    the strategy instead. What happens when your server certificate expires?
    Another software distribution? What about those clients you aren't able
    to reach with your distribution any more, for whatever reason? do you
    really want to cut them off at the knees?

    All your clients really need in their truststores is a root certificate
    to which your server certificate leads, and actually Java's truststore
    should already have one of those. It ships with lots of root certs for
    Verisign, CyberTrust, Equifax, Baltimore,Entrust, GeoTrust, Thawte, &c,
    and your certificate is almost certainly signed by someone whose cert
    chain leads back to one of those.
     
    EJP, May 24, 2006
    #2
    1. Advertising

  3. Tim Ward

    Tim Ward Guest

    "EJP" <> wrote in message
    news:FgZcg.10061$...
    > Tim Ward wrote:
    > >
    > > So, if I include the
    > > truststore in the jar file (along with the images and other resource

    files)
    > > how do I make the Java SSL system use it?

    >
    > You can do it by getting a javax.net.ssl.SSLContext via
    > SSLContext.getInstance, then call SSLContext.init(). The second
    > parameter is an array of TrustManagers. You can define your own
    > TrustManager ...


    I was beginning to think that was probably the way forward ... thanks for
    confirming it. (Before I'd written lots of code trying out various wrong
    approaches.)

    > However having said all that I would probably recommend that you rethink
    > the strategy instead. What happens when your server certificate expires?
    > Another software distribution?


    Well, not when any individual server certificate expires, only when the
    private root certificate is compromised ... in which case another
    distribution of my little application will be the least of my client's
    worries.

    > What about those clients you aren't able
    > to reach with your distribution any more, for whatever reason? do you
    > really want to cut them off at the knees?


    Not my decision, I just implement the spec. But the answer could well be
    something like: "yes, cutting them off is fine, because if they can't be
    reached for a software distribution they probably also can't be reached to
    be billed for their support contract".

    > All your clients really need in their truststores is a root certificate
    > to which your server certificate leads, and actually Java's truststore
    > ...ships with lots of root certs ...
    > and your certificate is almost certainly signed by someone whose cert
    > chain leads back to one of those.


    Nope, it's a private certificate hierarchy.

    Thanks again.

    --
    Tim Ward
    Brett Ward Limited - www.brettward.co.uk
     
    Tim Ward, May 24, 2006
    #3
  4. Tim Ward

    Tim Ward Guest

    "EJP" <> wrote in message
    news:FgZcg.10061$...
    > Tim Ward wrote:
    > >
    > > So, if I include the
    > > truststore in the jar file (along with the images and other resource

    files)
    > > how do I make the Java SSL system use it?

    >
    > You can do it by getting a javax.net.ssl.SSLContext via
    > SSLContext.getInstance, then call SSLContext.init(). The second
    > parameter is an array of TrustManagers. You can define your own
    > TrustManager to load your truststore from wherever you like, using in
    > your case java.security.KeyStore.load() from your truststore resource's
    > input stream, and implement the X509TrustManager API to respond
    > appropriately when SSL asks you any of those questions by looking in
    > that KeyStore. You then use that SSLContext to obtain your SSL socket
    > factories, use them to get your SSLSockets, and away you go.


    .... except that I don't want to try to understand how to write code to
    "implement the X509TrustManager API" because all that code already exists: I
    don't want any different algorithms to what's built in, only different data.

    Instead, why can't I:

    (1) get a TrustManagerFactory
    (2) make a KeyStore and load it from the resource as you say
    (3) use this KeyStore to init() the TrustManagerFactory
    (4) get the TrustManagerFactory to make me a TrustManager
    (5) pass this to SSLContext.init() and continue as you say

    ie, instead of writing code to implement X509TrustManager, get one from a
    customised TrustManagerFactory?

    In which case, all I need to know is which version of
    TrustManagerFactory.instance() to call and what parameters to pass it in
    order to obtain a TrustManagerFactory that will behave in exactly the same
    way as the default one except that it's got a different set of trusted root
    certificates? Ah, probably I just pass it getDefaultAlgorithm()?

    --
    Tim Ward
    Brett Ward Limited - www.brettward.co.uk
     
    Tim Ward, May 24, 2006
    #4
  5. Tim Ward

    Rogan Dawes Guest

    Tim Ward wrote:
    > "EJP" <> wrote in message
    > news:FgZcg.10061$...
    >> Tim Ward wrote:
    >>> So, if I include the
    >>> truststore in the jar file (along with the images and other resource

    > files)
    >>> how do I make the Java SSL system use it?

    >> You can do it by getting a javax.net.ssl.SSLContext via
    >> SSLContext.getInstance, then call SSLContext.init(). The second
    >> parameter is an array of TrustManagers. You can define your own
    >> TrustManager to load your truststore from wherever you like, using in
    >> your case java.security.KeyStore.load() from your truststore resource's
    >> input stream, and implement the X509TrustManager API to respond
    >> appropriately when SSL asks you any of those questions by looking in
    >> that KeyStore. You then use that SSLContext to obtain your SSL socket
    >> factories, use them to get your SSLSockets, and away you go.

    >
    > ... except that I don't want to try to understand how to write code to
    > "implement the X509TrustManager API" because all that code already exists: I
    > don't want any different algorithms to what's built in, only different data.
    >
    > Instead, why can't I:
    >
    > (1) get a TrustManagerFactory
    > (2) make a KeyStore and load it from the resource as you say
    > (3) use this KeyStore to init() the TrustManagerFactory
    > (4) get the TrustManagerFactory to make me a TrustManager
    > (5) pass this to SSLContext.init() and continue as you say
    >
    > ie, instead of writing code to implement X509TrustManager, get one from a
    > customised TrustManagerFactory?
    >
    > In which case, all I need to know is which version of
    > TrustManagerFactory.instance() to call and what parameters to pass it in
    > order to obtain a TrustManagerFactory that will behave in exactly the same
    > way as the default one except that it's got a different set of trusted root
    > certificates? Ah, probably I just pass it getDefaultAlgorithm()?
    >
    > --
    > Tim Ward
    > Brett Ward Limited - www.brettward.co.uk
    >
    >


    You may find the following article interesting:

    <http://www.devx.com/tips/Tip/30077>

    Obviously you don't need the GUI. But it shows a pretty minimal
    implementation of an X509TrustManager

    Regards,

    Rogan
     
    Rogan Dawes, May 24, 2006
    #5
  6. Tim Ward

    EJP Guest

    Tim Ward wrote:
    >
    > Instead, why can't I:
    >
    > ...
    >
    > ie, instead of writing code to implement X509TrustManager, get one from a
    > customised TrustManagerFactory?
    >
    > ...


    This all sounds OK, stupid of me not to think of it.
     
    EJP, May 25, 2006
    #6
  7. Tim Ward

    Tim Ward Guest

    "EJP" <> wrote in message
    news:J98dg.10227$...
    > Tim Ward wrote:
    > >
    > > Instead, why can't I:
    > > ...
    > >
    > > ie, instead of writing code to implement X509TrustManager, get one from

    a
    > > customised TrustManagerFactory?
    > > ...

    >
    > This all sounds OK, stupid of me not to think of it.


    For any future readers of this thread: that does in fact work.

    --
    Tim Ward
    Brett Ward Limited - www.brettward.co.uk
     
    Tim Ward, May 26, 2006
    #7
  8. Tim Ward

    chrispix

    Joined:
    Jul 22, 2006
    Messages:
    1
    not working for me

    I'm trying to do this very thing, but I still get the dreaded javax.net.ssl.SSLHandshakeException. Here's a snippet of my code. Am I interpreting you correctly?

    Code:
    // just to be sure
    System.clearProperty("javax.net.ssl.keyStore");
    
    TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
    KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
    InputStream keystoreStream = TestCreateSchedule.class.getResourceAsStream("/myTrust.jks");
    keystore.load(keystoreStream, null);
    trustManagerFactory.init(keystore);
    TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
    SSLContext sc = SSLContext.getInstance("SSL");
    sc.init(null, trustManagers, new java.security.SecureRandom());
    HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
    
    // using commons-httpclient to test
    HttpClient httpclient = new HttpClient();
    GetMethod httpget = new GetMethod("https://serverurl:8002/path/to/service");
    httpclient.executeMethod(httpget);
    
    I've verified that it is correctly reading myTrust.jks from the jar file, and that I can make a connection to https://serverurl:8002/path/to/service if I set the javax.net.ssl.keyStore system property to point to the keystore in the filesystem. Am I missing something?

    Here's the stack trace:

    Code:
    javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.Su
    nCertPathBuilderException: unable to find valid certification path to requested target
            at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Unknown Source)
            at com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(Unknown Source)
            at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Unknown Source)
            at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Unknown Source)
            at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(Unknown Source)
            at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(Unknown Source)
            at com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Unknown Source)
            at com.sun.net.ssl.internal.ssl.Handshaker.process_record(Unknown Source)
            at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(Unknown Source)
            at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(Unknown Source)
            at com.sun.net.ssl.internal.ssl.SSLSocketImpl.writeRecord(Unknown Source)
            at com.sun.net.ssl.internal.ssl.AppOutputStream.write(Unknown Source)
            at org.apache.commons.httpclient.HttpConnection$WrappedOutputStream.write(HttpConnection.java:1368)
            at java.io.BufferedOutputStream.flushBuffer(Unknown Source)
            at java.io.BufferedOutputStream.flush(Unknown Source)
            at org.apache.commons.httpclient.HttpConnection.flushRequestOutputStream(HttpConnection.java:799)
            at org.apache.commons.httpclient.HttpMethodBase.writeRequest(HttpMethodBase.java:2277)
            at org.apache.commons.httpclient.HttpMethodBase.processRequest(HttpMethodBase.java:2657)
            at org.apache.commons.httpclient.HttpMethodBase.execute(HttpMethodBase.java:1093)
            at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:675)
            at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:529)
    
     
    Last edited: Jul 24, 2006
    chrispix, Jul 22, 2006
    #8
  9. Tim Ward

    jacques

    Joined:
    Mar 19, 2007
    Messages:
    1
    Hi,

    You should try this :
    TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
    KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
    InputStream keystoreStream = ClassLoader.getSystemResourceAsStream("myTrust.jks");
    keystore.load(keystoreStream, "myPassword".toCharArray());
    trustManagerFactory.init(keystore);
    TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
    SSLContext sc = SSLContext.getInstance("SSL");
    sc.init(null, trustManagers, null);
    SSLContext.setDefault(sc);

    It works on my side with the axis librairy
     
    jacques, Mar 19, 2007
    #9
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. mike
    Replies:
    0
    Views:
    793
  2. Arnold Peters
    Replies:
    0
    Views:
    599
    Arnold Peters
    Jan 5, 2005
  3. oziris
    Replies:
    3
    Views:
    20,636
    Roedy Green
    Sep 30, 2005
  4. Marc
    Replies:
    0
    Views:
    362
  5. Christopher Wilson

    OpenSSL/SOAP - keystore/truststore

    Christopher Wilson, Mar 5, 2008, in forum: Ruby
    Replies:
    6
    Views:
    263
    Stephen Fickas
    Mar 6, 2008
Loading...

Share This Page