<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html;
      charset=windows-1252">
  </head>
  <body>
    <p>Thanks for reporting the bug and the detailed analysis.</p>
    <p>I have filed <a class="moz-txt-link-freetext" href="https://bugs.openjdk.java.net/browse/JDK-8246383">https://bugs.openjdk.java.net/browse/JDK-8246383</a> to
      keep track of this. Will aim to fix this for 15 and have it
      backported accordingly.</p>
    <p>Is it possible to get hold of an test provider to reproduce and
      verifying the fix?<br>
    </p>
    <p>Regards,</p>
    Valerie<br>
    <div class="moz-cite-prefix">On 6/2/2020 1:18 PM, John Gray wrote:<br>
    </div>
    <blockquote type="cite"
cite="mid:DM6PR11MB25859D5591C9F26853DD7574EE8B0@DM6PR11MB2585.namprd11.prod.outlook.com">
      <meta name="Generator" content="Microsoft Word 15 (filtered
        medium)">
      <div class="WordSection1">
        <p class="MsoNormal">Hello,</p>
        <p class="MsoNormal"> </p>
        <p class="MsoNormal">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. 
        </p>
        <p class="MsoNormal"> </p>
        <p class="MsoNormal">In JDK version 11.07 (and I also think Java
          12 and beyond), our toolkit reports the following error:</p>
        <p class="MsoNormal"><span>java.lang.RuntimeException:
            java.security.NoSuchAlgorithmException: Error constructing
            implementation (algorithm: X9_31usingAES256, provider:
            Entrust, class:
            com.entrust.toolkit.security.crypto.random.X9_31usingAES256)<br>
            at
java.base/java.security.SecureRandom.getDefaultPRNG(SecureRandom.java:281)<br>
            at
            java.base/java.security.SecureRandom.<init>(SecureRandom.java:219)<br>
            at
            java.base/javax.crypto.JceSecurity.<clinit>(JceSecurity.java:80)<br>
            ... 41 more<br>
            Caused by: java.security.NoSuchAlgorithmException: Error
            constructing implementation (algorithm: X9_31usingAES256,
            provider: Entrust, class:
            com.entrust.toolkit.security.crypto.random.X9_31usingAES256)<br>
            at
            java.base/java.security.Provider$Service.newInstance(Provider.java:1825)<br>
            at
            java.base/sun.security.jca.GetInstance.getInstance(GetInstance.java:236)<br>
            at
            java.base/sun.security.jca.GetInstance.getInstance(GetInstance.java:164)<br>
            at
            java.base/java.security.SecureRandom.getInstance(SecureRandom.java:365)<br>
            at
java.base/java.security.SecureRandom.getDefaultPRNG(SecureRandom.java:273)<br>
            ... 43 more<br>
            Caused by: java.lang.NullPointerException<br>
            <span>at
java.base/javax.crypto.JceSecurity.getVerificationResult(JceSecurity.java:203)</span><br>
            at
            java.base/javax.crypto.Cipher.getInstance(Cipher.java:690)<br>
            at
            java.base/javax.crypto.Cipher.getInstance(Cipher.java:625)<br>
            at
com.entrust.toolkit.security.crypto.random.X9_31usingAES256.initialize(X9_31usingAES256.java:524)<br>
            at
com.entrust.toolkit.security.crypto.random.X9_31usingAES256.<init>(X9_31usingAES256.java:102)<br>
            at
java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native
            Method)<br>
            at
java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)<br>
            at
java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)<br>
            at
java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:490)<br>
            at
            java.base/java.security.Provider.newInstanceUtil(Provider.java:176)<br>
            at
            java.base/java.security.Provider$Service.newInstance(Provider.java:1818)</span></p>
        <p class="MsoNormal"> </p>
        <p class="MsoNormal">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.</p>
        <p class="MsoNormal"><a
            href="https://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8228613"
            target="_blank" moz-do-not-send="true">https://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8228613</a></p>
        <p class="MsoNormal"> </p>
        <p class="MsoNormal">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.</p>
        <p class="MsoNormal"> </p>
        <p class="MsoNormal"><b><span>public</span></b><span>
          </span><b><span>static</span></b><span>
          </span><b><span>final</span></b><span> Cipher
            getInstance(String transformation,</span></p>
        <p class="MsoNormal"><span>                                          
            Provider provider)</span></p>
        <p class="MsoNormal"><span>           
          </span><b><span>throws</span></b><span>
            NoSuchAlgorithmException, NoSuchPaddingException</span></p>
        <p class="MsoNormal"><span>    {</span></p>
        <p class="MsoNormal"><span>       
          </span><b><span>if</span></b><span> ((transformation ==
          </span><b><span>null</span></b><span>) ||
            transformation.equals(</span><span>""</span><span>)) {</span></p>
        <p class="MsoNormal"><span>           
          </span><b><span>throw</span></b><span>
          </span><b><span>new</span></b><span> NoSuchAlgorithmException(</span><span>"Null
            or empty transformation"</span><span>);</span></p>
        <p class="MsoNormal"><span>        }</span></p>
        <p class="MsoNormal"><span>       
          </span><b><span>if</span></b><span> (provider ==
          </span><b><span>null</span></b><span>) {</span></p>
        <p class="MsoNormal"><span>           
          </span><b><span>throw</span></b><span>
          </span><b><span>new</span></b><span> IllegalArgumentException(</span><span>"Missing
            provider"</span><span>);</span></p>
        <p class="MsoNormal"><span>        }</span></p>
        <p class="MsoNormal"><span>        Exception failure =
          </span><b><span>null</span></b><span>;</span></p>
        <p class="MsoNormal"><span>        List<Transform>
            transforms = getTransforms(transformation);</span></p>
        <p class="MsoNormal"><span>       
          </span><b><span>boolean</span></b><span> providerChecked =
          </span><b><span>false</span></b><span>;</span></p>
        <p class="MsoNormal"><span>        String paddingError =
          </span><b><span>null</span></b><span>;</span></p>
        <p class="MsoNormal"><span>       
          </span><b><span>for</span></b><span> (Transform tr :
            transforms) {</span></p>
        <p class="MsoNormal"><span>            Service s =
            provider.getService(</span><span>"Cipher"</span><span>,
            tr.transform);</span></p>
        <p class="MsoNormal"><span>           
          </span><b><span>if</span></b><span> (s ==
          </span><b><span>null</span></b><span>) {</span></p>
        <p class="MsoNormal"><span>               
          </span><b><span>continue</span></b><span>;</span></p>
        <p class="MsoNormal"><span>            }</span></p>
        <p class="MsoNormal"><span>           
          </span><b><span>if</span></b><span> (providerChecked ==
          </span><b><span>false</span></b><span>) {</span></p>
        <p class="MsoNormal"><span>               
          </span><span>// for compatibility, first do the lookup and
            then verify</span><span></span></p>
        <p class="MsoNormal"><span>               
          </span><span>// the provider. this makes the difference
            between a NSAE</span><span></span></p>
        <p class="MsoNormal"><span>               
          </span><span>// and a SecurityException if the</span><span></span></p>
        <p class="MsoNormal"><span>               
          </span><span>// provider does not support the algorithm.</span><span></span></p>
        <p class="MsoNormal"><span>               
            <span>Exception ve =
              JceSecurity.getVerificationResult(provider);</span></span><span></span></p>
        <p class="MsoNormal"><span>                </span><b><span>if</span></b><span>
            (ve != </span><b><span>null</span></b><span>) {</span></p>
        <p class="MsoNormal"><span>                    String msg =
          </span><span>"JCE cannot authenticate the provider "</span><span></span></p>
        <p class="MsoNormal"><span>                        +
            provider.getName();</span></p>
        <p class="MsoNormal"><span>                   
          </span><b><span>throw</span></b><span>
          </span><b><span>new</span></b><span> SecurityException(msg,
            ve);</span></p>
        <p class="MsoNormal"><span>                }</span></p>
        <p class="MsoNormal"><span>                providerChecked =
          </span><b><span>true</span></b><span>;</span></p>
        <p class="MsoNormal"><span>            }</span></p>
        <p class="MsoNormal"><span> </span></p>
        <p class="MsoNormal"><span>The
            JceSecurity.getVerificationResult(provider) method is used
            when initializing the SecureRandom (first highlighted line
            below) when the classLoader is loading the JceSecurity class
            itself. </span></p>
        <p class="MsoNormal"><span> </span></p>
        <p class="MsoNormal"><span>From the JceSecurity class:</span></p>
        <p class="MsoNormal"><span> </span></p>
        <p class="MsoNormal"><b><span>static</span></b><span>
          </span><b><span>final</span></b><span> SecureRandom RANDOM =
          </span><b><span>new</span></b><span> SecureRandom();</span><span></span></p>
        <p class="MsoNormal"><span> </span></p>
        <p class="MsoNormal"><span>   
          </span><span>// The defaultPolicy and exemptPolicy will be set
            up</span><span></span></p>
        <p class="MsoNormal"><span>   
          </span><span>// in the static initializer.</span><span></span></p>
        <p class="MsoNormal"><span>   
          </span><b><span>private</span></b><span>
          </span><b><span>static</span></b><span> CryptoPermissions
            defaultPolicy =
          </span><b><span>null</span></b><span>;</span></p>
        <p class="MsoNormal"><span>   
          </span><b><span>private</span></b><span>
          </span><b><span>static</span></b><span> CryptoPermissions
            exemptPolicy =
          </span><b><span>null</span></b><span>;</span></p>
        <p class="MsoNormal"><span> </span></p>
        <p class="MsoNormal"><span>    </span><span>//
            Map<Provider,?> of the providers we already have
            verified</span><span></span></p>
        <p class="MsoNormal"><span>   
          </span><span>// value == PROVIDER_VERIFIED is successfully
            verified</span><span></span></p>
        <p class="MsoNormal"><span>   
          </span><span>// value is failure cause Exception in error case</span><span></span></p>
        <p class="MsoNormal"><span>   
          </span><b><span>private</span></b><span>
          </span><b><span>static</span></b><span>
          </span><b><span>final</span></b><span> Map<Provider,
            Object> verificationResults =</span></p>
        <p class="MsoNormal"><span>           
          </span><b><span>new</span></b><span>
            IdentityHashMap<>();</span><span></span></p>
        <p class="MsoNormal"><span> </span></p>
        <p class="MsoNormal"><span>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. 
          </span></p>
        <p class="MsoNormal"><span> </span></p>
        <p class="MsoNormal"><span>The fix to the issue should be
            simple, just move the initialization of the
            verificationResults Map BEFORE the SecureRandom
            initialization in JceSecurity.java</span></p>
        <p class="MsoNormal"><span> </span></p>
        <p class="MsoNormal"><span>Because verificationResults is not
            initialized, the line highlighted below fails (Because the
            Map has not been initialized).</span></p>
        <p class="MsoNormal"><span>/*</span><span></span></p>
        <p class="MsoNormal"><span>     * Verify that the provider JAR
            files are signed properly, which</span><span></span></p>
        <p class="MsoNormal"><span>     * means the signer's certificate
            can be traced back to a</span><span></span></p>
        <p class="MsoNormal"><span>     * JCE trusted CA.</span><span></span></p>
        <p class="MsoNormal"><span>     * Return null if ok, failure
            Exception if verification failed.</span><span></span></p>
        <p class="MsoNormal"><span>     */</span><span></span></p>
        <p class="MsoNormal"><span>   
          </span><b><span>static</span></b><span>
          </span><b><span>synchronized</span></b><span> Exception
            getVerificationResult(Provider p) {</span></p>
        <p class="MsoNormal"><span>       
            <span>Object o = verificationResults.get(p);</span></span><span></span></p>
        <p class="MsoNormal"><span>       
          </span><b><span>if</span></b><span> (o == PROVIDER_VERIFIED) {</span></p>
        <p class="MsoNormal"><span>           
          </span><b><span>return</span></b><span>
          </span><b><span>null</span></b><span>;</span></p>
        <p class="MsoNormal"><span>        }
          </span><b><span>else</span></b><span>
          </span><b><span>if</span></b><span> (o !=
          </span><b><span>null</span></b><span>) {</span></p>
        <p class="MsoNormal"><span>           
          </span><b><span>return</span></b><span> (Exception)o;</span></p>
        <p class="MsoNormal"><span>        }</span></p>
        <p class="MsoNormal"><span>       
          </span><b><span>if</span></b><span> (verifyingProviders.get(p)
            !=
          </span><b><span>null</span></b><span>) {</span></p>
        <p class="MsoNormal"><span>           
          </span><span>// this method is static synchronized, must be
            recursion</span><span></span></p>
        <p class="MsoNormal"><span>           
          </span><span>// return failure now but do not save the result</span><span></span></p>
        <p class="MsoNormal"><span>           
          </span><b><span>return</span></b><span>
          </span><b><span>new</span></b><span> NoSuchProviderException(</span><span>"Recursion
            during verification"</span><span>);</span></p>
        <p class="MsoNormal"><span>        }</span></p>
        <p class="MsoNormal"><span>       
          </span><b><span>try</span></b><span> {</span></p>
        <p class="MsoNormal"><span>            verifyingProviders.put(p,
            Boolean.FALSE);</span></p>
        <p class="MsoNormal"><span>            URL providerURL =
            getCodeBase(p.getClass());</span></p>
        <p class="MsoNormal"><span>           
            verifyProvider(providerURL, p);</span></p>
        <p class="MsoNormal"><span>           
          </span><span>// Verified ok, cache result</span><span></span></p>
        <p class="MsoNormal"><span>           
            verificationResults.put(p, PROVIDER_VERIFIED);</span></p>
        <p class="MsoNormal"><span>           
          </span><b><span>return</span></b><span>
          </span><b><span>null</span></b><span>;</span></p>
        <p class="MsoNormal"><span>        }
          </span><b><span>catch</span></b><span> (Exception e) {</span></p>
        <p class="MsoNormal"><span>           
            verificationResults.put(p, e);</span></p>
        <p class="MsoNormal"><span>           
          </span><b><span>return</span></b><span> e;</span></p>
        <p class="MsoNormal"><span>        }
          </span><b><span>finally</span></b><span> {</span></p>
        <p class="MsoNormal"><span>           
            verifyingProviders.remove(p);</span></p>
        <p class="MsoNormal"><span>        }</span></p>
        <p class="MsoNormal"><span>    }</span></p>
        <p class="MsoNormal"> </p>
        <p class="MsoNormal"><span>Cheers,</span></p>
        <p class="MsoNormal"><span> </span></p>
        <p class="MsoNormal"><span>John Gray</span></p>
        <p class="MsoNormal"><span>  </span></p>
        <p class="MsoNormal"><span> </span></p>
        <p class="MsoNormal"> </p>
        <p class="MsoNormal"> </p>
      </div>
    </blockquote>
  </body>
</html>