PKCS #11 provider shutdown process, key zeroization
Matthew Hall
mhall at mhcomputing.net
Mon Mar 18 22:13:01 UTC 2013
It's great to hear from you, Milton! Below I have placed everything into one
report in order of importance. Perhaps someone could take a look at let me
know what the solution is if there are some, and how we could work together to
correct anything that could be an issue.
1. Correct procedure for PKCS11 provider shutdown and reload
How do you shutdown the provider, zeroize all keys and passwords, and reopen
it, without restarting the whole JVM?
Also, assuming you can't shutdown and restart, why is the secure shutdown and
finalization code comments out and not called, with just XXX and no
explanation of why it was disabled? It's very important for FIPS that
everything is shut down properly so things aren't left sitting around in
memory.
The details for this are rather long to describe, see below signature for more
detail.
2. Code which logs contents of Private Keys in toString() by default
Quite a number of bits of code are printing out the content of the private
exponent of the RSA Private Keys by default into the toString() output, which
could lead to key compromise if they're printed into a log.
share/classes/sun/security/pkcs11/P11Key.java:552: sb.append("\n private exponent: ");
share/classes/sun/security/pkcs11/P11Key.java:624: sb.append("\n private exponent: ");
share/classes/sun/security/rsa/RSAPrivateCrtKeyImpl.java:238: sb.append("\n private exponent: ");
share/classes/sun/security/rsa/RSAPrivateKeyImpl.java:105: + n + "\n private exponent: " + d;
Ordinarily I believe FIPS and PCI would require that there isn't any code
sitting around that could accidentally or unexpectedly print out the private
key data. Is this toString() behaving that way for a good reason?
3. Key and password zeroization
A number of pieces of code 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.
Thanks,
Matthew.
More detail on (1): Correct procedure for PKCS11 provider shutdown and reload
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?
Regards,
Matthew.
More information about the security-dev
mailing list