Re: BCJSSE, JDK5 and SSLSocketFactory.getDefault()
Veit Guna <[email protected]>
| Newsgroups | gmane.comp.encryption.bouncy-castle.devel |
|---|---|
| Message-ID | <[email protected]> |
One thing I forgot to implement was createSocket() - which wasn't
obvious and led to an exception during other usecases. Here's the
missing method:
@Override
public Socket createSocket() throws IOException {
return sslContext.getSocketFactory().createSocket();
}
Am 04.06.2018 um 19:45 schrieb Veit Guna:
> For other people maybe trying to get this done using JDK5 as well,
> here's a small snippet that worked for me.
>
> It's no beauty (no autocloseables since JDK5 etc.), but one should get
> the idea. It's working for me, automatically hooking into a standard
> HttpsUrlConnection.
> Keep in mind that setting
> 'ssl.SocketFactory.provider=fancy.pants.BcSslSocketFactory' in
> java.security is required in order to make this work.
> If it fails with IllegalKeySize or similar, remember to have JCE strong
> encryption policy files in place.
>
> Thanks again for this great library!
>
> --cut here--
>
> package fancy.pants;
>
> import java.io.File;
> import java.io.FileInputStream;
> import java.io.IOException;
> import java.io.InputStream;
> import java.net.InetAddress;
> import java.net.Socket;
> import java.net.UnknownHostException;
> import java.security.KeyManagementException;
> import java.security.KeyStore;
> import java.security.KeyStoreException;
> import java.security.NoSuchAlgorithmException;
> import java.security.NoSuchProviderException;
> import java.security.UnrecoverableKeyException;
> import java.security.cert.CertificateException;
>
> import javax.net.ssl.KeyManagerFactory;
> import javax.net.ssl.SSLContext;
> import javax.net.ssl.SSLSocketFactory;
> import javax.net.ssl.TrustManagerFactory;
>
> import org.bouncycastle.jsse.provider.BouncyCastleJsseProvider;
>
> public class BcSslSocketFactory extends SSLSocketFactory {
>
> private static final String DEFAULT_PASSWORD = "changeit";
>
> private SSLContext sslContext;
>
> public BcSslSocketFactory() throws IOException, KeyStoreException,
> NoSuchProviderException, NoSuchAlgorithmException, CertificateException,
> UnrecoverableKeyException, KeyManagementException{
>
> String provider =
> System.getProperty("javax.net.ssl.keyStoreProvider");
> String keystoreType =
> System.getProperty("javax.net.ssl.keyStoreType", KeyStore.getDefaultType());
>
> KeyStore keystore = null;
> if (provider != null) {
> keystore = KeyStore.getInstance(keystoreType, provider);
> } else {
> keystore = KeyStore.getInstance(keystoreType);
> }
>
> String keystorePath =
> System.getProperty("javax.net.ssl.trustStore",
> System.getProperty("java.home") + "/lib/security/cacerts".replace('/',
> File.separatorChar));
> String keystorePassword =
> System.getProperty("javax.net.ssl.trustStorePassword", DEFAULT_PASSWORD);
>
> InputStream keystoreInputStream = null;
> try {
> keystoreInputStream = new FileInputStream(keystorePath);
> keystore.load(keystoreInputStream,
> keystorePassword.toCharArray());
> } finally {
> if (keystoreInputStream != null) {
> keystoreInputStream.close();
> }
> }
>
> KeyManagerFactory kmf =
> KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
> kmf.init(keystore, keystorePassword.toCharArray());
>
> sslContext = SSLContext.getInstance("TLS", new
> BouncyCastleJsseProvider());
>
> TrustManagerFactory trustMgrFact =
> TrustManagerFactory.getInstance("PKIX", "BCJSSE");
> trustMgrFact.init(keystore);
>
> sslContext.init(null, trustMgrFact.getTrustManagers(), null);
> }
>
> @Override
> public Socket createSocket(Socket arg0, String arg1, int arg2,
> boolean arg3) throws IOException {
> return sslContext.getSocketFactory().createSocket(arg0, arg1,
> arg2, arg3);
> }
>
> @Override
> public String[] getDefaultCipherSuites() {
> return sslContext.getSocketFactory().getDefaultCipherSuites();
> }
>
> @Override
> public String[] getSupportedCipherSuites() {
> return sslContext.getSocketFactory().getSupportedCipherSuites();
> }
>
> @Override
> public Socket createSocket(String arg0, int arg1) throws
> IOException, UnknownHostException {
> return sslContext.getSocketFactory().createSocket(arg0, arg1);
> }
>
> @Override
> public Socket createSocket(InetAddress arg0, int arg1) throws
> IOException {
> return sslContext.getSocketFactory().createSocket(arg0, arg1);
> }
>
> @Override
> public Socket createSocket(String arg0, int arg1, InetAddress arg2,
> int arg3) throws IOException, UnknownHostException {
> return sslContext.getSocketFactory().createSocket(arg0, arg1,
> arg2, arg3);
> }
>
> @Override
> public Socket createSocket(InetAddress arg0, int arg1, InetAddress
> arg2, int arg3) throws IOException {
> return sslContext.getSocketFactory().createSocket(arg0, arg1,
> arg2, arg3);
> }
> }
> --cut here--
>
>
> Am 02.06.2018 um 16:40 schrieb Veit Guna:
>> Hi.
>>
>> I've succesfully integrated BCJSSE programmatically using JDK5 and
>> HttpsUrlConnection being able to finally connect to TLSv1.2 webservices.
>>
>> Basically by creating the SSLContext using the BCJSSE provider and
>> initializing it using a TrustManagerFactory and KeyManagerFactory.
>> Then getting the SSLSocketFactory via context.getSSLSocketFactory(); and
>> setting it on the HttpsUrlConnection.
>>
>> So far so good. Now I'm wondering, how to achieve the same result,
>> without having to touch any code :).
>> Since HttpsUrlConnection and e.g. Apache Commons HttpClient are using
>> SSLSocketFactory.getDefault(), I currently don't see a way to do this in
>> JDK5.
>>
>> The BCJSSE documentation I found here:
>>
>> https://downloads.bouncycastle.org/fips-java/BC-FJA-(D)TLSUserGuide-1.0.0.pdf
>>
>> states, that getDefault() will only return the BCJSSE SSLSocketFactory,
>> if the Provider is registered before the Sun JSSE one in java.security.
>> I tried it, but it didn't work out. It still returns the Sun JSSE one.
>>
>> Taking a look at the JDK5 SSLSocketFactory.getDefault() implementation
>> shows, that it tries to load a povider, specified via
>> 'ssl.SocketFactory.provider' system property.
>> But this requires a no-args ctor, which the BC package private
>> ProvSSLSocketFactory doesn't provide. So this would fail if one would
>> try to override the default one.
>>
>> Not specifying it via system property, defaults to
>> 'com.sun.net.ssl.internal.ssl.SSLSocketFactoryImpl' which is then
>> instantiated and used.
>> Now I'm wondering, how SSLSockerFactory.getDefault(); should ever return
>> the BC one :D.
>>
>> Could somebody please shed some light on this, how the mechanism
>> described in the doc works for JDK5?
>>
>> All I could imagine would be, to create my own SSLSocketFactory Provider
>> implementation, setting up the BC SSLContext within that and returning
>> the BC SSLSocketFactory
>> from it. Then registering it via mentioned system property. Any other
>> ways to do it?
>>
>> Cheers,
>> Veit
>>
>>
>>
>>
>>
>>
>>