t.pimentel t.pimentel - 19 days ago 14
Java Question

How to access a url that requires a SafeNet eToken certificate using Java

Good afternoon,

I have a SafeNet 5100 eToken already with a valid certificate in it that I use to access a web application from my company that requires it.

When I try to access the web application using a web browser (like chrome) everything works fine and I have no problem. A dialog from SafeNet opens up, I put in my password and I am able to access the site.

What I'm trying to do now is to access this web application through a java program (I'm programming it using the IDE eclipse) and couldn't find how to do this. Is there any API from SafeNet to do this or any online tutorials?

I was looking at this thread how to use Microsoft Crypto API with USB Dongle following PKCS#11, but couldn't understand how this CryptoAPI CSP works. Any help is appreciated.

Thank you

Answer

I found out how to do this thanks to these two threads:

How to get KeyStore from usb token in Java
java keytool with opensc pkcs#11 provider only works with debug option enabled

And this website:

Pdf Signing Using eToken in java

First, if the website has a certificate java doesn't trust by default you have to create a trustStore and load it to java's System properties. you can see how to do it in here:

Oracle - Generating a KeyStore and TrustStore (using keytool)

Than you have to find where the PKCS#11 library used for your smartCard/eToken is installed in your computer, in mine it is in "C:\Windows\System32\eTPKCS11.dll". Then create a .cfg file like this:

name=SafeNet
library=C:\Windows\System32\eTPKCS11.dll
slot=4

Where you give it a name and the path to your PKCS#11 library. Slot is the slot where your eToken/SmartCard is connected (you don't need to set this if you don't want).

Now my code looks like this:

System.setProperty("javax.net.ssl.trustStore", "cfgFiles/trustedHttpsCertificates.truestore");
System.setProperty("javax.net.ssl.trustStoreType", "jks");
System.setProperty("javax.net.ssl.trustStorePassword", "oiadad");

Provider newProvider = new SunPKCS11("cfgFiles/etpkcs11.cfg");
Security.addProvider(newProvider);

try {
    KeyStore keyStore = KeyStore.getInstance("PKCS11");
    keyStore.load(null, "".toCharArray());

    KeyManagerFactory keyFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
    keyFactory.init(keyStore,null);

    SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
    sslContext.init(keyFactory.getKeyManagers(), null, null);
    sslSocketFactory = sslContext.getSocketFactory();

} catch (KeyStoreException e) {
    e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
    e.printStackTrace();
} catch (CertificateException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
} catch (NoSuchProviderException e) {
    e.printStackTrace();
} catch (UnrecoverableKeyException e1) {
    e1.printStackTrace();
} catch (KeyManagementException e1) {
    e1.printStackTrace();
}

I first tell java where to look for my trustStore. Then I pass the path to my cfg file, create a provider with it and tell security that this new provider exists.

After this I initialize and load a PKCS11 KeyStore giving it a blank password (could pass my real password if I wanted, but this way a SafeNet pop window shows up and asks me for my password).

Then I instantiate a KeyManagerFactory and a SSLSocketFactory. This is the last step to using your eToken to be able to access multi-factor authentication https urls.

Now there's just one more trick to access a protected https website, you have to give the HttpsURLConnection the new SSLSocketFactory. You can do it like this:

try {
    HttpsURLConnection conn = (HttpsURLConnection)new URL(<your-https-url-here>).openConnection();
    conn.setRequestMethod("GET");
    conn.setDoInput(true);
    conn.setSSLSocketFactory(sslSocketFactory);

    int responseCode = conn.getResponseCode();
    System.out.println("RESPONSE: " + responseCode);

    InputStream inputstream = conn.getInputStream();
    InputStreamReader inputstreamreader = new InputStreamReader(inputstream);
    BufferedReader bufferedreader = new BufferedReader(inputstreamreader);

    String line = null;
    String htmlResponse = "";

    while ((line = bufferedreader.readLine()) != null) {
        htmlResponse += line + "\n";
        //System.out.println("html: " + line);
    }
} catch (ProtocolException e) {
    e.printStackTrace();
} catch (MalformedURLException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
}

I hope this helps anyone having problems with eTokens or SmartCards.

Comments