Hi, John,
Thanks for the reply.
Yes, your understanding is correct. I expect the fix for JDK-8246613
will be backported into other releases.
BTW, if you have spare time for the test provider, it'd help speeding up
the fix for JDK-8246383. If not, it's ok as well. Just may take longer
to get to it.
Regards,
Valerie
On 6/10/2020 1:31 PM, John Gray wrote:
Thanks Valerie!
If I understand you correctly, I think you are saying the fix for
https://bugs.openjdk.java.net/browse/JDK-8246613 will mean the first
SecureRandom in the provider will be used as the default (which will
make it equivalent to JDK 11.06 and previous versions). If that is
the case, I agree it should mitigate the issue and would be ok with
lowering the priority of 8246383.
Will this new fix be back-ported into 11 LTS versions as well?
Thanks so much for your amazing fast response. I have been trying to
set aside some time to put together a simple sample you can use to
verify 8246383 (that doesn’t require our full toolkit), but haven’t
been able to find the time to do that yet.
Cheers,
John Gray
*From:*Valerie Peng [mailto:valerie.p...@oracle.com]
*Sent:* Wednesday, June 10, 2020 4:14 PM
*To:* John Gray <john.g...@entrustdatacard.com>;
security-dev@openjdk.java.net
*Cc:* Muthu Kannappan <mu...@entrustdatacard.com>; Raj Arora
<raj.ar...@entrustdatacard.com>
*Subject:* [EXTERNAL]Re: NullPointer in
JceSecurity.getVerificationResult - Affects JDK 11.07, and JDK 12 and
later.
*WARNING:* This email originated outside of Entrust Datacard.
*DO NOT CLICK* links or attachments unless you trust the sender and
know the content is safe.
------------------------------------------------------------------------
Hi John,
As you may have noticed, we are progressing a fix for
https://bugs.openjdk.java.net/browse/JDK-8246613
<https://bugs.openjdk.java.net/browse/JDK-8246613> for returning the
same default SecureRandom algo for 3rd party providers as in
pre-JDK7092821 releases. Thus, the chance of observing JDK-8246613
should be lowered significantly. Given this, I plan to lower the
priority of JDK-8246383 and it may not be fixed in JDK 15 as earlier
communicated.
If this will be an issue, please let me know.
Thanks,
Valerie
On 6/2/2020 4:37 PM, Valerie Peng wrote:
Thanks for reporting the bug and the detailed analysis.
I have filed https://bugs.openjdk.java.net/browse/JDK-8246383 to
keep track of this. Will aim to fix this for 15 and have it
backported accordingly.
Is it possible to get hold of an test provider to reproduce and
verifying the fix?
Regards,
Valerie
On 6/2/2020 1:18 PM, John Gray wrote:
Hello,
At Entrust Datacard, we produce a Java based toolkit that
contains our own Security Provider. This toolkit and
provider has been around for about 19 years.
In JDK version 11.07 (and I also think Java 12 and beyond),
our toolkit reports the following error:
java.lang.RuntimeException:
java.security.NoSuchAlgorithmException: Error constructing
implementation (algorithm: X9_31usingAES256, provider:
Entrust, class:
com.entrust.toolkit.security.crypto.random.X9_31usingAES256)
at
java.base/java.security.SecureRandom.getDefaultPRNG(SecureRandom.java:281)
at
java.base/java.security.SecureRandom.<init>(SecureRandom.java:219)
at
java.base/javax.crypto.JceSecurity.<clinit>(JceSecurity.java:80)
... 41 more
Caused by: java.security.NoSuchAlgorithmException: Error
constructing implementation (algorithm: X9_31usingAES256,
provider: Entrust, class:
com.entrust.toolkit.security.crypto.random.X9_31usingAES256)
at
java.base/java.security.Provider$Service.newInstance(Provider.java:1825)
at
java.base/sun.security.jca.GetInstance.getInstance(GetInstance.java:236)
at
java.base/sun.security.jca.GetInstance.getInstance(GetInstance.java:164)
at
java.base/java.security.SecureRandom.getInstance(SecureRandom.java:365)
at
java.base/java.security.SecureRandom.getDefaultPRNG(SecureRandom.java:273)
... 43 more
Caused by: java.lang.NullPointerException
at
java.base/javax.crypto.JceSecurity.getVerificationResult(JceSecurity.java:203)
at java.base/javax.crypto.Cipher.getInstance(Cipher.java:690)
at java.base/javax.crypto.Cipher.getInstance(Cipher.java:625)
at
com.entrust.toolkit.security.crypto.random.X9_31usingAES256.initialize(X9_31usingAES256.java:524)
at
com.entrust.toolkit.security.crypto.random.X9_31usingAES256.<init>(X9_31usingAES256.java:102)
at
java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native
Method)
at
java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at
java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at
java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:490)
at
java.base/java.security.Provider.newInstanceUtil(Provider.java:176)
at
java.base/java.security.Provider$Service.newInstance(Provider.java:1818)
I investigated this error, and found it was made possible
because of the following change in Java 11.07 which unmasked a
bug in the JVM that has probably been around for years.
https://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8228613
It is a problem inside the JceSecurity class. When the class
is being loaded, the call to setup a default SecureRandom()
instance is invoked. That seems to invoke the JVM to find
the first available SecureRandom() instance. This error
happens when our Entrust provider is in first position. In
previous versions of the JDK it honoured the order of
algorithms specified in the providers. In our Entrust
Security provider, we have a number of SecureRandom
implementations. Now because of the above change, it picks a
different SecureRandom instance (the X9_31usingAES256). That
should be fine, however the problem is that the SecureRandom()
setup calls Cipher.getInstance() and as you can see below,
that calls JceSecurity.getVerificationResult() which is
static, and uses the verificationResuts Map that has not yet
been initialized (becasuse it’s declaration is after the
SecureRandom setup). That is why there is a
NullPointerException.
*public* *static* *final* Cipher getInstance(String
transformation,
Provider provider)
*throws* NoSuchAlgorithmException, NoSuchPaddingException
{
*if* ((transformation == *null*) || transformation.equals("")) {
*throw* *new* NoSuchAlgorithmException("Null or empty
transformation");
}
*if* (provider == *null*) {
*throw* *new* IllegalArgumentException("Missing provider");
}
Exception failure = *null*;
List<Transform> transforms =
getTransforms(transformation);
*boolean* providerChecked = *false*;
String paddingError = *null*;
*for* (Transform tr : transforms) {
Service s = provider.getService("Cipher",
tr.transform);
*if* (s == *null*) {
*continue*;
}
*if* (providerChecked == *false*) {
// for compatibility, first do the lookup and
then verify
// the provider. this makes the difference
between a NSAE
// and a SecurityException if the
// provider does not support the algorithm.
Exception ve =
JceSecurity.getVerificationResult(provider);
*if* (ve != *null*) {
String msg = "JCE cannot authenticate the
provider "
+ provider.getName();
*throw* *new* SecurityException(msg, ve);
}
providerChecked = *true*;
}
The JceSecurity.getVerificationResult(provider) method is used
when initializing the SecureRandom (first highlighted line
below) when the classLoader is loading the JceSecurity class
itself.
From the JceSecurity class:
*static* *final* SecureRandom RANDOM = *new* SecureRandom();
// The defaultPolicy and exemptPolicy will be set up
// in the static initializer.
*private* *static* CryptoPermissions defaultPolicy = *null*;
*private* *static* CryptoPermissions exemptPolicy = *null*;
// Map<Provider,?> of the providers we already have verified
// value == PROVIDER_VERIFIED is successfully verified
// value is failure cause Exception in error case
*private* *static* *final* Map<Provider, Object>
verificationResults =
*new* IdentityHashMap<>();
It fails when it calls the following code in JceSecurity.java
because the verificationResults Map<Provider, Object> has not
been initialized because the SecureRandom() constructor ends
up calling the JceSecurity.getVerificationResult() static
method that makes use of the Map! That explains the
NullPointerException.
The fix to the issue should be simple, just move the
initialization of the verificationResults Map BEFORE the
SecureRandom initialization in JceSecurity.java
Because verificationResults is not initialized, the line
highlighted below fails (Because the Map has not been
initialized).
/*
* Verify that the provider JAR files are signed properly,
which
* means the signer's certificate can be traced back to a
* JCE trusted CA.
* Return null if ok, failure Exception if verification
failed.
*/
*static* *synchronized* Exception
getVerificationResult(Provider p) {
Object o = verificationResults.get(p);
*if* (o == PROVIDER_VERIFIED) {
*return* *null*;
} *else* *if* (o != *null*) {
*return* (Exception)o;
}
*if* (verifyingProviders.get(p) != *null*) {
// this method is static synchronized, must be
recursion
// return failure now but do not save the result
*return* *new* NoSuchProviderException("Recursion during
verification");
}
*try* {
verifyingProviders.put(p, Boolean.FALSE);
URL providerURL = getCodeBase(p.getClass());
verifyProvider(providerURL, p);
// Verified ok, cache result
verificationResults.put(p, PROVIDER_VERIFIED);
*return* *null*;
} *catch* (Exception e) {
verificationResults.put(p, e);
*return* e;
} *finally* {
verifyingProviders.remove(p);
}
}
Cheers,
John Gray