1

I'm using sunPkcs11 class to connect my app to NetHsm. My local service nFast runs on port 9004. It is used as bridge to communicate with the NetHsm.

My provider is set like that:

Provider provider =  new sun.security.pkcs11.SunPKCS11(pkcs11ConfigFile);  // name = nCipher, library = D:\Program\nCipher\nfast\toolkits\pkcs11\cknfast-64.dll

And I decipher like that:

KeyStore ks = KeyStore.getInstance("PKCS11", provider);
ks.load(null, password);
Key key = ks.getKey(keyId, null);
IvParameterSpec paramSpec = new IvParameterSpec(iv);
AlgorithmParameters algParams = AlgorithmParameters.getInstance("AES");
algParams.init(paramSpec);
Cipher ci = Cipher.getInstance("AES/CBC/NoPadding", provider);
ci.init(Cipher.DECRYPT_MODE, key, algParams);
ci.doFinal(dataToDecipher);

All is right, I can decipher my keys.

Now, I stop the service nFast. I get an exception because it is impossible to decipher my keys. Normal ...

java.security.ProviderException: update() failed
Caused by: sun.security.pkcs11.wrapper.PKCS11Exception: CKR_DEVICE_ERROR

I restart the service and I would like to be able to decipher again my keys but I get an exception:

java.security.ProviderException: update() failed
Caused by: sun.security.pkcs11.wrapper.PKCS11Exception: CKR_GENERAL_ERROR
at sun.security.pkcs11.wrapper.PKCS11.C_FindObjectsInit(Native Method)
at sun.security.pkcs11.P11KeyStore.findObjects(P11KeyStore.java:2673)
at sun.security.pkcs11.P11KeyStore.mapLabels(P11KeyStore.java:2288)
at sun.security.pkcs11.P11KeyStore.engineLoad(P11KeyStore.java:770)

I'm obliged to restart my app.

How can I re-initialize the provider in order to communicate again with the service without restarting the app?

wit
  • 11
  • 2

2 Answers2

0

Java KeyStore api doesn't have a neat way of finalizing a session with a PKCS#11 device. When you create your provider instance, it intializes the session with the token, and there is no way you can finalize the opened session once you are done interacting with the token using the KeyStore api.

If you finalize your opened session before you restart the service, you may not face this issue. Provided you have to reinitialze the session again (you have to create the provider instance again).

You can refer to my answer here where I was able to solve a similar issue related to the session.

Since the KeyStore api doesn't provide a method like finalize, you can do the below workaround from the post mentioned.

PKCS11 pkcs11 = PKCS11.getInstance(((sun.security.pkcs11.SunPKCS11) provider).getProperty("pkcs11LibraryPath"), null, null, true);
pkcs11.C_Finalize(PKCS11Constants.NULL_PTR);

Note the setProperty I did for the provider instance.

always_a_rookie
  • 4,515
  • 1
  • 25
  • 46
  • I've got a compilation error with PKCS11.getInstance. I don't find this method in IAIK library. I have replace it with PKCS11Connector.connectToPKCS11Module(String) – wit May 31 '17 at 14:44
  • The `PKCS11` is from `sun.security.pkcs11.wrapper` package. – always_a_rookie May 31 '17 at 14:46
  • It is an 'IAIK PKCS#11 Wrapper' solution which is under licence. I'm searching for an official Sun solution delivered with Java. Thus, your code is not up-to-date. PKCS11.getInstance does not compil. It seems we must use: PKCS11 pkcs11 = PKCS11Connector.connectToPKCS11Module(library); – wit May 31 '17 at 15:05
  • If it doesn't compile because of access restriction, you could follow this fix: https://stackoverflow.com/questions/5172069/access-restriction-on-sun-security-pkcs11-sunpkcs11 – always_a_rookie May 31 '17 at 15:09
0

In the same given way of always_a_rookie_to_learn, I found the final solution.

Thanks to this other post here

I'm now able to open several time the provider by purging session and token at each call. So bad that C_Finalize do not do the job in moduleMap.

import sun.security.pkcs11.wrapper.PKCS11;
import sun.security.pkcs11.wrapper.PKCS11Constants;

// Open provider
Provider provider = new sun.security.pkcs11.SunPKCS11(pkcs11ConfigFile);

// Do what you need
...

// Finalize the pkcs11 driver in the wrapper
PKCS11 pkcs11 = PKCS11.getInstance(library, null, null, true);
pkcs11.C_Finalize(PKCS11Constants.NULL_PTR);            

// Clean the pkcs11 driver in the wrapper to force C_Initialize next time
Field moduleMapField = PKCS11.class.getDeclaredField("moduleMap");  
moduleMapField.setAccessible(true);  
Map<?, ?> moduleMap = (Map<?, ?>) moduleMapField.get(pkcs11LibraryPath);  
moduleMap.clear();
wit
  • 11
  • 2