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 (multi-factor authentication).
I'm creating a desktop application to access this website. I am already able to add the website's certificate to the TrustStore
and get my certificate into a KeyStore
.
What I've got so far is:
System.setProperty("javax.net.ssl.trustStore", "U:\\Certificados\\efau.truestore");
System.setProperty("javax.net.ssl.trustStoreType", "jks");
System.setProperty("javax.net.ssl.trustStorePassword", "oiadad");
KeyManagerFactory kFac;
SSLContext sslContext;
SSLSocketFactory sockFactory = null;
KeyStore ks;
try {
// load keystore present in windows and print aliases found (only one, so nextElement always prints same information (name of certificate inside usb token I want to open))
ks = KeyStore.getInstance("Windows-MY", "SunMSCAPI");
ks.load(null, null);
System.out.println(ks.aliases().nextElement());
System.out.println(ks.aliases().nextElement());
// try to load my certificate specifically from all certificates and passes necessary token password to it
InputStream in = IOUtils.toInputStream(ks.aliases().nextElement(), "UTF-8");
System.out.println(in);
ks.load(in, password);
// print certificate to check if I have it
System.out.println(ks.getCertificate(ks.aliases().nextElement()));
// get ssl context and key manager factory
sslContext = SSLContext.getInstance("SSL", "SunJSSE");
kFac = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kFac.init(ks,null);
sslContext.init(kFac.getKeyManagers(), null, null);
sockFactory = sslContext.getSocketFactory();
// start connection with website
HttpsURLConnection conn = (HttpsURLConnection)new URL(<my-https-url>).openConnection();
conn.setRequestMethod("GET");
conn.setDoInput(true);
conn.setSSLSocketFactory(sockFactory);
int responseCode = conn.getResponseCode();
System.out.println("RESPONSE: " + responseCode);
} 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();
}
When I run this code I get:
javax.net.ssl.SSLHandshakeException: Received fatal alert: decrypt_error
at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Unknown Source)
at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Unknown Source)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.recvAlert(Unknown Source)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(Unknown Source)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(Unknown Source)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(Unknown Source)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(Unknown Source)
at sun.net.www.protocol.https.HttpsClient.afterConnect(Unknown Source)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(Unknown Source)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(Unknown Source)
at java.net.HttpURLConnection.getResponseCode(Unknown Source)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getResponseCode(Unknown Source)
at receita.system.monitoring.Ping.main(Ping.java:313)
And I get this error when I type the correct password for the token and when I type a wrong one, so I think I'm never passing it the password in the correct way.
Why am I receiving the exception?
--------- Updated ---------
I created a config file with the following information pointing to my PKCS11.dll library:
name = Aladdin
library = C:/WINDOWS/system32/eTPKCS11.dll
And in the main function I add:
SunPKCS11 newProvider = new SunPKCS11("u:/Certificados/etpkcs11.cfg");
Provider a = newProvider;
Security.addProvider(a);
KeyStore ks;
try {
ks = KeyStore.getInstance("PKCS11");
...
}
And now I'm getting this as an error:
java.security.KeyStoreException: PKCS11 not found
at java.security.KeyStore.getInstance(Unknown Source)
at receita.system.monitoring.Ping.main(Ping.java:292)
Caused by: java.security.NoSuchAlgorithmException: PKCS11 KeyStore not available
at sun.security.jca.GetInstance.getInstance(Unknown Source)
at java.security.Security.getImpl(Unknown Source)
... 2 more
I also tried to modify Keystore.getInstance to:
ks = KeyStore.getInstance("PKCS11", a);
and then I get this different error:
java.security.KeyStoreException: PKCS11 not found
at java.security.KeyStore.getInstance(Unknown Source)
at receita.system.monitoring.Ping.main(Ping.java:292)
Caused by: java.security.NoSuchAlgorithmException: no such algorithm: PKCS11 for provider SunPKCS11-Aladdin
at sun.security.jca.GetInstance.getService(Unknown Source)
at sun.security.jca.GetInstance.getInstance(Unknown Source)
at java.security.Security.getImpl(Unknown Source)
... 2 more
--------- Updated 2 (Working Code) ---------
My final working code is:
System.setProperty("javax.net.ssl.trustStore", "U:\\Certificados\\efau.truestore");
System.setProperty("javax.net.ssl.trustStoreType", "jks");
System.setProperty("javax.net.ssl.trustStorePassword", "oiadad");
KeyManagerFactory kFac;
SSLContext sslContext;
SSLSocketFactory sockFactory = null;
SunPKCS11 providerMSCAPI = new SunPKCS11("u:/Certificados/etpkcs11.cfg");
Provider a = providerMSCAPI;
Security.addProvider(a);
KeyStore ks;
try {
ks = KeyStore.getInstance("PKCS11");
ks.load(null, password);
InputStream in = IOUtils.toInputStream(ks.aliases().nextElement(), "UTF-8");
ks.load(in, password);
sslContext = SSLContext.getInstance("SSL", "SunJSSE");
kFac = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kFac.init(ks,null);
sslContext.init(kFac.getKeyManagers(), null, null);
sockFactory = sslContext.getSocketFactory();
HttpsURLConnection conn = (HttpsURLConnection)new URL(/*<my-url>*/).openConnection();
conn.setRequestMethod("GET");
conn.setDoInput(true);
conn.setSSLSocketFactory(sockFactory);
int responseCode = conn.getResponseCode();
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";
}
} 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();
}
And I have to or set the debug argument in run configurations:
-Djava.security.debug=sunpkcs11
Or set the slot in the .cfg file:
name=SafeNet
library=C:\Windows\System32\eTPKCS11.dll
slot=4