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

Reply via email to