We are using the apache httpclient code to create a custom https URL handler. The URL handler is registered with the JRE early in platform startup. so when a component in our platform opens a https connection, it is calling our https URLhandler instead of the default JRE URL handler.
Our https URL handler works fine for a site with a CA issued certificate. (eg. opening a https client connection to https://bugs.eclipse.org/bugs/ works fine). But doesn't work if the user wants to create his own keystore and import the certificate in that keystore and then initialize the sslContext. Here is the user code : FileInputStream fis = new FileInputStream(truststore_loc); CertificateFactory cf = CertificateFactory.getInstance("X.509" ); java.security.cert.Certificate c = cf.generateCertificate(fis); KeyStore ks = KeyStore.getInstance("JCEKS"); TrustManagerFactory tmf = TrustManagerFactory.getInstance( TrustManagerFactory.getDefaultAlgorithm()); ks.load(null, null); ks.setCertificateEntry("agentAlias", c); tmf.init(ks); SSLContext ctx; ctx = SSLContext.getInstance("SSL"); ctx.init(null, tmf.getTrustManagers(), null); This works fine when opening a https connection using JRE default https URL handler. But when we use our https URL handler, we get the following error: javax.net.ssl.SSLHandshakeException: com.ibm.jsse2.util.h: PKIX path building failed: java.security.cert.CertPathBuilderException: unable to find valid certification path to requested target at com.ibm.jsse2.n.a(n.java:17) at com.ibm.jsse2.jc.a(jc.java:541) at com.ibm.jsse2.db.a(db.java:403) at com.ibm.jsse2.db.a(db.java:278) at com.ibm.jsse2.eb.a(eb.java:137) at com.ibm.jsse2.eb.a(eb.java:157) at com.ibm.jsse2.db.m(db.java:243) at com.ibm.jsse2.db.a(db.java:280) at com.ibm.jsse2.jc.a(jc.java:104) at com.ibm.jsse2.jc.g(jc.java:470) at com.ibm.jsse2.jc.a(jc.java:291) at com.ibm.jsse2.j.write(j.java:21) at java.io.BufferedOutputStream.flushBuffer( BufferedOutputStream.java:88) at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:146) at org.apache.commons.httpclient.HttpConnection.flushRequestOutputStream( HttpConnection.java:827) at org.apache.commons.httpclient.HttpMethodBase.writeRequest( HttpMethodBase.java:1975) at org.apache.commons.httpclient.HttpMethodBase.execute( HttpMethodBase.java:993) at org.apache.commons.httpclient.HttpMethodDirector.executeWithRetry( HttpMethodDirector.java:397) at org.apache.commons.httpclient.HttpMethodDirector.executeMethod( HttpMethodDirector.java:170) at org.apache.commons.httpclient.HttpClient.executeMethod( HttpClient.java:396) at org.apache.commons.httpclient.HttpClient.executeMethod( HttpClient.java:324) I took a look at the apache ssl guide and it says: The default behavior of HttpClient is suitable for most uses, however there are some aspects which you may want to configure. The most common requirements for customizing SSL are: Ability to accept self-signed or untrusted SSL certificates. This is highlighted by an SSLException with the message Unrecognized SSL handshake (or similar) being thrown when a connection attempt is made. You want to use a third party SSL library instead of Sun's default implementation. In our case, we are using IBM JSSE, which is third party SSL lib. I tried the EasySSLProtocolSocketFactory, but that seems accept any certificate. If I try to create other custom ProtocolSocketFactory and register the protocol(Protocol.registerProtocol("https", new Protocol("https", new MySSLSocketFactory(), 443)); it only search the certifcate in the key store URL specified in the custom protocolsocketFactory. As a result, connect to https://bugs.eclipse.org/bugs/ would not work since the certificate is stored in the default cacerts. Right now, our workaround is to ask the user to import the certifcate into the JRE keystore(cacerts ). Does anyone know how to make the apache http client code working with a certificate imported from a keystore other than cacerts? thanks a lot! Michelle
