<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html;
      charset=windows-1252">
  </head>
  <body>
    <p>Hi John,</p>
    <p>As you may have noticed, we are progressing a fix for
      <a class="moz-txt-link-freetext" href="https://bugs.openjdk.java.net/browse/JDK-8246613">https://bugs.openjdk.java.net/browse/JDK-8246613</a> 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. <br>
    </p>
    <p>If this will be an issue, please let me know.</p>
    Thanks,<br>
    Valerie<br>
    <div class="moz-cite-prefix">On 6/2/2020 4:37 PM, Valerie Peng
      wrote:<br>
    </div>
    <blockquote type="cite"
      cite="mid:651b2416-4764-d460-e3f9-56ef073a5c35@oracle.com">
      <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"
          moz-do-not-send="true">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>
    </blockquote>
  </body>
</html>