Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Client Cert Smartcard Authentication #117

Open
lukeherron opened this issue May 25, 2016 · 4 comments
Open

Client Cert Smartcard Authentication #117

lukeherron opened this issue May 25, 2016 · 4 comments

Comments

@lukeherron
Copy link

I'm attempting to get jBrowserDriver working with a site that requires client cert authentication via smartcard (which holds an unextractable private key). I'm using the IAIK PKCS#11 wrapper to handle the signing, and am setting the following so that the keystore and truststore are pointing at the card (as per: http://docs.oracle.com/javase/8/docs/technotes/guides/security/p11guide.html#JSSE):

        System.setProperty("javax.net.ssl.trustStore", "NONE");
        System.setProperty("javax.net.ssl.trustStoreType", "PKCS11");
        System.setProperty("javax.net.ssl.trustStoreProvider", "IAIK PKCS#11:1");
        System.setProperty("javax.net.ssl.keyStore", "NONE");
        System.setProperty("javax.net.ssl.keyStoreType", "PKCS11");
        System.setProperty("javax.net.ssl.keyStoreProvider", "IAIK PKCS#11:1");

Browsing other issues, I've also tried:

        System.setProperty("jbd.rmi.javax.net.ssl.trustStore", "NONE");
        System.setProperty("jbd.rmi.javax.net.ssl.trustStoreType", "PKCS11");
        System.setProperty("jbd.rmi.javax.net.ssl.trustStoreProvider", "IAIK PKCS#11:1");
        System.setProperty("jbd.rmi.javax.net.ssl.keyStore", "NONE");
        System.setProperty("jbd.rmi.javax.net.ssl.keyStoreType", "PKCS11");
        System.setProperty("jbd.rmi.javax.net.ssl.keyStoreProvider", "IAIK PKCS#11:1");

When manually configuring the SSLContext, KeyManager and TrustManager, and connecting via an SSLSocket, the handshake completes successfully, the request is sent and a response received.

When attempting connection via jBrowserDriver I'm receiving:

[Port 55250; Process 1] May 25, 2016 10:12:29 PM com.sun.webkit.network.URLLoader doRun
[Port 55250; Process 1] WARNING: Unexpected error
[Port 55250; Process 1] java.io.IOException: java.security.cert.CertificateException: No X509TrustManager implementation available: <website>
[Port 55250; Process 1]     at com.machinepublishers.jbrowserdriver.StreamConnection.exec(StreamConnection.java:343)
[Port 55250; Process 1]     at com.machinepublishers.jbrowserdriver.StreamConnection.getResponseCode(StreamConnection.java:441)
[Port 55250; Process 1]     at com.sun.webkit.network.URLLoader.receiveResponse(URLLoader.java:414)
[Port 55250; Process 1]     at com.sun.webkit.network.URLLoader.doRun(URLLoader.java:163)
[Port 55250; Process 1]     at com.sun.webkit.network.URLLoader.lambda$run$93(URLLoader.java:128)
[Port 55250; Process 1]     at java.security.AccessController.doPrivileged(Native Method)
[Port 55250; Process 1]     at com.sun.webkit.network.URLLoader.run(URLLoader.java:127)
[Port 55250; Process 1]     at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)
[Port 55250; Process 1]     at java.util.concurrent.FutureTask.run(Unknown Source)
[Port 55250; Process 1]     at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
[Port 55250; Process 1]     at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
[Port 55250; Process 1]     at java.lang.Thread.run(Unknown Source)

I've ensured there is no ssl setting passed in the settings builder, as you've mentioned that Java will use the default SSLContext. Researching the exception hasn't led to any definitive resolution, and my knowledge is already pretty limited in this area, so my question is this: is any further configuration of jBrowserDriver required for this exception/scenario, or is this likely to be outside the jBrowserDriver scope? Would there be any expectation of jBrowserDriver working with client cert's on smart cards?

Cheers!

@hollingsworthd
Copy link
Owner

I'm curious what is involved with "manually configuring the SSLContext, KeyManager and TrustManager" ... note that the actual browser is run in a separate Java process, so any changes at runtime you're making to the Java network stack won't have effect on the child Java process. The properties will be passed if they're prepended with jbd.rmi (or the newer preferred method of using Settings.builder().javaOptions("-Dsome.option=somevalue"))

Also the HTTP requests are done using Apache HttpComponents. Most of that is configured here. Maybe comparing that file to what you're doing will offer some insight into why this isn't working. It should ideally and is in scope. Happy to hear more and would patch the project.

@hollingsworthd
Copy link
Owner

It uses the same JRE though so changes done on the command line with keytool should have an effect on the child process.

@lukeherron
Copy link
Author

I'm basing this off the IAIK workflow, so I'm unsure what the differences are likely to be if working purely with Java JSSE, but to get a successful handshake requires adding two providers via Security.addProvider(). One of these is the IAIK PKCS11 provider, which is used to initialise the KeyStore.

Once the KeyStore is initialised, the SSLContext.getInstance("TLS") call is made, and then the KeyManagerFactory is created and initialised with the keystore, and similarly the TrustManagerFactory

A good example of this process is shown in IAIK's demo example: https://git.io/vr1CO

I took a look at StreamConnectionClient.java and was able to get jBrowserDriver to successfully complete the handshake and return the correct data by adding the following to the sslContext() method:


            Properties properties = new Properties();
            properties.put(Constants.PKCS11_NATIVE_MODULE, <.so or .dll of smartcard driver>);
            IAIKPkcs11 pkcs11Provider = new IAIKPkcs11(properties);
            IAIK jceProvider = new IAIK();
            Security.addProvider(pkcs11Provider);
            Security.addProvider(jceProvider);
            KeyStore keyStore = KeyStore.getInstance("PKCS11KeyStore");
            keyStore.load(new ByteArrayInputStream(pkcs11Provider.getName().getBytes()), null);
            SSLContext context = SSLContext.getInstance("TLS");
            KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
            kmf.init(keyStore, null);
            TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
            tmf.init(keyStore);
            //I'm using a trust all manager for this test, as I'm still getting a "No trusted certificate found" error when using tmf.getTrustManagers(), which I'll look into seperately
            //context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
            context.init(kmf.getKeyManagers(), new X509TrustManager[] { new X509TrustManager() {
              public X509Certificate[] getAcceptedIssuers() {
                return null;
              }

              public void checkClientTrusted(X509Certificate[] chain, String authType) {
              }

              public void checkServerTrusted(X509Certificate[] chain, String authType) {
              }
            }}, null);
            return context;

This required me to pass in an ssl string to the Settings builder in order to trigger the sslContext() method, as well as introduce the IAIK dependencies to the class. I'm happy to have this working in my instance (thanks for pointing me in the right direction), but any suggestions on how to better implement this functionality welcome.

@hollingsworthd
Copy link
Owner

hollingsworthd commented May 26, 2016

That's great it's working. Maybe I can add a feature to let people pass in a plugin to handle SSL loaded from the classpath, or pass a serialized object directly. The IAIKPkcs11 dependency will load no problem because the child process attempts to use the same classpath as the parent.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants