Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Null Pointer Exception for deserialized object of class ProvSecretKeySpec from the old BC-FIPS version 1.0.1 with the newer version 1.0.2.4 #1628

Open
yusuf4u52 opened this issue Apr 16, 2024 · 7 comments
Assignees

Comments

@yusuf4u52
Copy link

I have secretKey serialized and store in the keystore file with the older version of bc-fips jar 1.0.1.

But when a deserialized the file with the newer version of the jar 1.0.2.4 I get NullPointerException for getKey.
This is due to missing property private final AtomicBoolean hasBeenDestroyed = new AtomicBoolean(false); in the deserialized object.

What are my migration options?

@cipherboy
Copy link
Collaborator

cipherboy commented Apr 16, 2024

@yusuf4u52 Do you have an example key store (not with real keys!) you'd mind sharing? Also the full stack trace would be appreciated. Is this the BCFKS or the Java keystore (JKS)?

(I'm having a hard time seeing how this would be triggered without a reproducer, in particular. hasBeenDestroyed is constructed in newer versions via setting it directly in the class, so it should never be null. And the BCFKS encrypts the contents of the key and uses a secret key factory to parse it, which means we're not serializing/deserializing the key instance/class (and thus, could have a missing attribute/parameter if we were say, JSON encoding), but instead the encoded contents of the raw key (usually just a byte array)).

@yusuf4u52
Copy link
Author

It is Java JCEKS keystore and I am attaching the sample keystore file.

What I meant to say is that the deserialization works but the ProvSecretKeySpec object I get has hasBeenDestroyed set to null and so the getEncoded or any other get method on ProvSecretKeySpec returns Null Pointer Exception.

keystore.zip

I will paste the stack trace in a bit.

@cipherboy cipherboy self-assigned this Apr 16, 2024
@yusuf4u52
Copy link
Author

Throwable=[java.lang.NullPointerException
org.bouncycastle.jcajce.provider.ProvSecretKeySpec.isDestroyed(Unknown Source)
org.bouncycastle.jcajce.provider.KeyUtil.checkDestroyed(Unknown Source)
org.bouncycastle.jcajce.provider.ProvSecretKeySpec.getFormat(Unknown Source)
java.base/java.security.Provider$Service.supportsKeyFormat(Unknown Source)
java.base/java.security.Provider$Service.supportsParameter(Unknown Source)
java.base/javax.crypto.Cipher.chooseProvider(Unknown Source)
java.base/javax.crypto.Cipher.init(Unknown Source)
java.base/javax.crypto.Cipher.init(Unknown Source)

@yusuf4u52
Copy link
Author

Throwable=[java.lang.NullPointerException
org.bouncycastle.jcajce.provider.ProvSecretKeySpec.isDestroyed(Unknown Source)
org.bouncycastle.jcajce.provider.KeyUtil.checkDestroyed(Unknown Source)
org.bouncycastle.jcajce.provider.ProvSecretKeySpec.getEncoded(Unknown Source)

@cipherboy
Copy link
Collaborator

@yusuf4u52 Sorry, mind giving me a hint as to what the keystore/entry passwords are? :-)

But I think I see the issue either way: https://github.com/openjdk/jdk/blob/master/src/java.base/share/classes/com/sun/crypto/provider/JceKeyStore.java uses https://github.com/openjdk/jdk/blob/master/src/java.base/share/classes/javax/crypto/SealedObject.java (https://docs.oracle.com/javase/8/docs/api/javax/crypto/SealedObject.html), which as the docs point out:

Given any Serializable object, one can create a SealedObject that encapsulates the original object, in serialized format (i.e., a "deep copy"), and seals (encrypts) its serialized contents, using a cryptographic algorithm such as AES, to protect its confidentiality. The encrypted content can later be decrypted (with the corresponding algorithm using the correct decryption key) and de-serialized, yielding the original object.

While ProvSecretKeySpec is nominally Serializable, it (and everywhere else) doesn't handle adding new attributes so it isn't cross version Serializable. ProvSecretKeySpec.readObject would need to set hasBeenDestroyed properly.

Is using BCFKS possible? I think, because it doesn't use SealedObject, it won't have this issue. Though the migration path would look like:

  1. Load JCEKS on bc 1.0.1
  2. Write keys using BCFKS
  3. Load from BCFKS on 1.0.2.4.

Notably, the 1.0.2 usage guide doesn't say the use of the JKS with secret keys is allowed... So I think using BCFKS would be most ideal.

@dghgit
Copy link
Contributor

dghgit commented Apr 17, 2024

Okay, so the earlier keys didn't implement destroyable. I think you should be able to convert the key store to BCFKS - it will handle AES, Camellia, TripleDES, ARIA, SEED, and HMAC keys.

If it's not one of those, you'll need to convert it by hand. You could use a custom version of the FIPS provider which dealt with the missing field and then reserialise it, at which point you'll find the key store should work with 1.0.2.4.

@yusuf4u52
Copy link
Author

Yes the ProvSecretKeySpec.readObject would need to set hasBeenDestroyed properly.

I am thinking of going the custom version route.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants