Hello, I am working on a product which uses the Sun PKCS #11 provider. I was curious how the FIPS mode worked, in particular about the shutdown procedure and whether or not it performed key and password zeroization, so I was reading through the OpenJDK 7 trunk version of the implementation code to learn more.
In share/classes/sun/security/pkcs11/wrapper/PKCS11.java we have some methods: private static native void finalizeLibrary(); I could not find any code which ever called this method. In share/native/sun/security/pkcs11/wrapper/p11_general.c, all the implementation code for this native method is commented out, with an XXX marker but no explanation why it's commented out. public native void C_Finalize(Object pReserved) throws PKCS11Exception; I could not find any code which ever called this either, but at least the implementation code is not commented out, and looks like it would probably work if it was called. I believe that this method often implements zeroization so it seems like it could be an issue if nothing is ever calling this. /** * Calls disconnect() to cleanup the native part of the wrapper. Once this * method is called, this object cannot be used any longer. Any subsequent * call to a C_* method will result in a runtime exception. * * @exception Throwable If finalization fails. */ public void finalize() throws Throwable { disconnect(); } Next we have the finalizer, which calls the disconnect method. Note that it is documented as throwing an exception, but any exceptions during finalization would be ignored and not reported anywhere, which would mean we would not have a way of knowing that unloading is failing and nothing is getting zeroized properly. (This is according to Object#finalize documentation). Is there a way to obtain a reference to the PKCS11 wrapper and call this function explicitly? I could not find a good way to do it. Since finalize might never get called if the object never gets unreferences, I can't see how we could be sure the keys are zeroized right, even if some of the items inside of disconnect perform the zeroization, which I'm not sure that they do. /** * Disconnects the PKCS#11 library from this object. After calling this * method, this object is no longer connected to a native PKCS#11 module * and any subsequent calls to C_ methods will fail. This method is for * internal use only. * Declared private, because incorrect handling may result in errors in the * native part. * * @preconditions * @postconditions */ private native void disconnect(); Let's take a look at the implementation of disconnect from solaris/native/sun/security/pkcs11/wrapper/p11_md.c: /* * Class: sun_security_pkcs11_wrapper_PKCS11 * Method: disconnect * Signature: ()V */ JNIEXPORT void JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_disconnect (JNIEnv *env, jobject obj) { ModuleData *moduleData; TRACE0("DEBUG: disconnecting module..."); moduleData = removeModuleEntry(env, obj); if (moduleData != NULL) { dlclose(moduleData->hModule); } free(moduleData); TRACE0("FINISHED\n"); } If you read through removeModuleEntry, the only interesting operation performed there is: (*env)->SetLongField(env, pkcs11Implementation, pNativeDataID, 0); This is setting the pNativeDataID field from the PKCS #11 class to zero. Then, the higher code in disconnect will dlclose the library. However dlclose is only reference-counting, and does not guarantee the library will be removed from memory, or that the removed memory will be zeroized. In addition if the keys are stored in a dynamic area and not a static area inside the library, which is what I suspect, they could still be present in memory after this point, which seems to be against what's required for zeroization in FIPS. Therefore I am asking now, if we are sure that the way all of this works will perform the key zeroization we expect. Can anybody comment on whether this could be an actual issue or not? In addition, I noticed there are a number of pieces of code that are zeroizing keys using \x20 instead of \x00: share/classes/com/sun/crypto/provider/PBEKey.java:70: java.util.Arrays.fill(passwd, ' '); share/classes/com/sun/crypto/provider/PBEKeyFactory.java:151: java.util.Arrays.fill(passwdChars, ' '); share/classes/com/sun/jmx/remote/security/FileLoginModule.java:561: Arrays.fill(password, ' '); share/classes/com/sun/security/auth/module/LdapLoginModule.java:1000: Arrays.fill(password, ' '); share/classes/java/io/Console.java:84: * java.util.Arrays.fill(passwd, ' '); share/classes/java/io/Console.java:388: Arrays.fill(rcb, 0, len, ' '); share/classes/java/security/KeyStore.java:297: Arrays.fill(password, ' '); share/classes/sun/net/www/protocol/http/spnego/NegotiateCallbackHandler.java:91: if (password != null) Arrays.fill(password, ' '); share/classes/sun/security/pkcs11/P11KeyStore.java:253: Arrays.fill(password, ' '); share/classes/sun/security/pkcs11/SunPKCS11.java:1191: Arrays.fill(pin, ' '); share/classes/sun/security/util/Password.java:104: Arrays.fill(lineBuffer, ' '); share/classes/sun/security/util/Password.java:118: Arrays.fill(buf, ' '); share/classes/sun/security/util/Password.java:123: Arrays.fill(consoleEntered, ' '); share/classes/sun/security/util/PolicyUtil.java:174: Arrays.fill(keyStorePassword, ' '); Officially I don't think this is allowed either, but it's a more minor issue than the other item I'm asking about. Regards, Matthew.