3 Replies Latest reply on Apr 22, 2012 9:03 AM by EJP

    Connecting to an SSL URL after adding certificate to Trust Manager.


      I am connecting to a https site, getting the certificate and adding it to the trust manager as follows:
      private void registerCertificate(){
           URL url = new URL("https://abc.abc");
           KeyStore keyStore = KeyStore.getInstance(KeyStore
           if (keyStoreBytes == null) {
                System.out.println("Keystore is null");
                keyStore.load(null, null);
           } else {
                keyStore.load(new ByteArrayInputStream(keyStoreBytes),
           TrustManagerFactory tmf = TrustManagerFactory
           X509TrustManager defaultTrustManager = (X509TrustManager) tmf
           SavingTrustManager tm = new SavingTrustManager(
           SSLContext context = SSLContext.getInstance("TLS");
           context.init(null, new TrustManager[] { tm }, null);
           SSLSocketFactory factory = context.getSocketFactory();
           SSLSocket socket = (SSLSocket) factory.createSocket(url
                     .getHost(), url.getPort() == -1 ? url.getDefaultPort()
                     : url.getPort());
           try {
                socket.setEnabledProtocols(new String[] { "SSLv3" });
           } catch (SSLException e) {
                X509Certificate[] chain = tm.chain;
                for (int i = 0; i < chain.length; i++) {
                     System.out.println("Adding the certificate to the keystore");
                     System.out.println("URL Host: " + url.getHost());
                     System.out.println("Chain: " + tm.chain);
                     keyStore.setCertificateEntry(url.getHost() + " - " + i,
                ByteArrayOutputStream bos = new ByteArrayOutputStream();
                keyStore.store(bos, password);
                keyStoreBytes = bos.toByteArray();
                createAndRegisterProtocol(keyStoreBytes, password);
                System.out.println("Certificate added to the key store.");

      private void createAndRegisterProtocol(byte[] byteArray, char[] password)
                throws Exception {
           KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
           ks.load(new ByteArrayInputStream(byteArray), password);

           SSLContext context = SSLContext.getInstance("TLS");
           TrustManagerFactory tmf = TrustManagerFactory
           X509TrustManager defaultTrustManager = (X509TrustManager) tmf
           context.init(null, new TrustManager[] { defaultTrustManager }, null);
           SSLSocketFactory factory = context.getSocketFactory();

           Protocol myhttps = new Protocol("https",
                     new ProtocolSocketFactoryImplementation(factory), 443);

           Protocol.registerProtocol("https", myhttps);

      From what I can see the certificate is retrieved and added to the trustmanager. However, when I try to access the URL using:

      URL url = new URL("https://abc.abc");
      sp.parse(new InputSource(url.openStream()), this);

      I still get the error:
      javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

      I am not very familiar with network programming in Java.

      If anyone has any idea about what I might be doing wrong here or how I can debug I would greatly appreciate it.

      Many Thanks

      Edited by: 929182 on Apr 20, 2012 1:09 PM

      Edited by: sabre150 on Apr 20, 2012 10:03 PM
      Moderator action : added code tags to improve readability
        • 1. Re: Connecting to an SSL URL after adding certificate to Trust Manager.
          What you at doing is radically insecure. It breaks the SSL security model and exposes you to man in the middle attacks. It would be irresponsible to tell you why it doesn't work and how to to get it working.
          • 2. Re: Connecting to an SSL URL after adding certificate to Trust Manager.
            Thanks for the advice.

            Could you give me a link that gives the best practice? The only solutions I'm coming across on the web are:
            1. Manually add the certificate to the cacerts file where the application is running
            2. Accepting all certificates regardless of they come from.

            I'd like to avoid the first solution if possible as deployment will be overly complicated trying to get it set up on the machines where the application is running.

            Note that the application is connecting to the web service within a WAN.

            Many Thanks
            • 3. Re: Connecting to an SSL URL after adding certificate to Trust Manager.
              Neither of those is a 'solution'. They are bandaid approaches to 'get it working' that are used by people who don't know what they are talking about and who don't appreciate the consequences, which are severe: (a) evidence of incompetence on the part of the implementors, (b) complete loss of legal non-repudiability of transactions via the system, ... They are part of the security problem, and they make it worse in the way I described.

              The solution is to not to communicate via SSL with entities that cannot be trusted to be what they say they are. That means either:

              1. Communicating with a server whose certificate is signed by a trusted certificate authority, or

              2. If the server for some (probably bad) reason insists on using a self-signed certificate, acquire it off-line and import it into the clients' truststores.

              Not the 'offline' part. You cannot logically acquire security credentials over the same channel that relies on them to make it secure. It is a contradiction in terms.

              If you"re not prepared to take the steps that are required to make SSL secure, there is no point in using SSL at all: you may as well use a plaintext connection.