JDK-8248505 : Unexpected NoSuchAlgorithmException when using secure random impl from BCFIPS provider
  • Type: Bug
  • Component: security-libs
  • Sub-Component: java.security
  • Affected Version: 8u261,11.0.8-oracle,14.0.2,15,16
  • Priority: P2
  • Status: Closed
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2020-06-29
  • Updated: 2022-06-27
  • Resolved: 2020-07-07
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 11 JDK 13 JDK 14 JDK 15 JDK 16 JDK 8
11.0.10-oracleFixed 13.0.4Fixed 14.0.2Fixed 15 b31Fixed 16Fixed 8u261Fixed
Related Reports
Duplicate :  
Duplicate :  
Duplicate :  
Relates :  
Relates :  
Description
Reported through OpenJDK:
Since the latest changes to SecureRandom[0], using certain ( I can reproduce with one but others might have the same issue, see below ) security providers, it is impossible to get an instance of SecurityRandom. The following is reproducible with the BouncyCastle FIPS 140-2 provider [1]:

public class TestSecureRandom {

    public static void main(String[] args){
        assert Security.getProviders()[0].getName().equals("BCFIPS");
        SecureRandom random = new SecureRandom();
    }
}

will fail with

Exception in thread "main" java.lang.RuntimeException: java.security.NoSuchAlgorithmException: Service not registered with Provider BCFIPS: BCFIPS: SecureRandom.DEFAULT -> org.bouncycastle.jcajce.provider.random.DefSecureRandom
  attributes: {ImplementedIn=Software}

        at java.base/java.security.SecureRandom.getDefaultPRNG(SecureRandom.java:294)
        at java.base/java.security.SecureRandom.<init>(SecureRandom.java:219)
        at TestSecureRandomBug.main(TestSecureRandomBug.java:8)
Caused by: java.security.NoSuchAlgorithmException: Service not registered with Provider BCFIPS: BCFIPS: SecureRandom.DEFAULT -> org.bouncycastle.jcajce.provider.random.DefSecureRandom
  attributes: {ImplementedIn=Software}

        at java.base/java.security.Provider$Service.newInstance(Provider.java:1857)
        at java.base/java.security.SecureRandom.getDefaultPRNG(SecureRandom.java:290)
        ... 2 more


I reported this to the authors of the security provider [2] and I will share part of the analysis on why this fails here for the sake of completeness of the report.

The BCFIPS security provider overrides getService() and getServices() of Provider and it has its own extension of the Provider.Service which getService() returns.
However, getDefaultSecureRandomService() will always return a java.security.Provider.Service and since we are calling newInstance [3] on it, this fails as the

if (provider.getService(type, algorithm) != this) {
    throw new NoSuchAlgorithmException("Service not registered with Provider " + provider.getName() + ": " + this);
}

can not be true. getService will return a org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider.BcService and `this` is a java.security.Provider.Service.


I am not aware of other providers being affected by this ( the non FIPS BouncyCastle Provider is not, since it's a legacy style security provider ) but given the reason for the issue, I think there might be others affected. With [0] being backported to all supported versions and BCFIPS being one of the few available security providers that is FIPS 140-2 approved, this introduces a significant issue for folks with fips compliance requirements.

One potential fix that was proposed in [2] was to replace

        if (prngServices != null && !prngServices.isEmpty()) {
            return prngServices.iterator().next();
        }

with:

        if (prngServices != null && !prngServices.isEmpty()) {
            Service rng = prngServices.iterator().next();
            return getService(rng.getType(), rng.getAlgorithm());
        }

so that any provider extending Service, could work fine.

Best Regards
Ioannis

[0] https://hg.openjdk.java.net/jdk/jdk15/rev/6eeaa40131ff
[1] https://www.bouncycastle.org/fips-java/
[2] http://bouncy-castle.1462172.n4.nabble.com/Default-SecureRandom-issue-in-BCFIPS-and-latest-JDK15-td4659964.html
[3] https://hg.openjdk.java.net/jdk/jdk15/rev/6eeaa40131ff#l2.55
Comments
Fix request (13u) I would like to backport this change into 13.0.4 because this release is affected by the problem, and for parity with 11u. The original change applies cleanly.
14-07-2020

jdk11 backport request I would like to have the patch as well in OpenJDK11 (for better parity with 11.0.8 and because the issue is present there too). The patch applies cleanly.
09-07-2020

Fix Request (for 14.0.2) SecureRandom impl from BCFIPS provider cannot be instantiated as a side effect of JDK-8246613. As SecureRandom is used by many security algorithms and there is no workaround for BCFIPS provider, this may be a blocker for applications relying on BCFIPS provider for FIPS 140-2 support. Fixed java.security.Provider class to re-query the impl through public API so the instantiation check should not fail. Enhanced regression test accordingly and no test failures from mach5. Risk Analysis : Low Patch from jdk15 applied cleanly.
07-07-2020

URL: https://hg.openjdk.java.net/jdk/jdk15/rev/a8e947a5be91 User: valeriep Date: 2020-07-07 16:57:49 +0000
07-07-2020

Well, I initially feel that this should just be corner cases. Turns out it seems to impact more providers than expected. None of JDK providers override putService()/getService() and then also do legacy registration, nor do we anticipate the need for doing so. As part of webrev for this bug, I enhanced the java/security/SecureRandom/DefaultAlgo.java regression test with a custom provider following the BCFIPS provider behavior. Not sure what Entrust provider does, will clarify with them over the OpenJDK alias.
02-07-2020

The main reason which BCFIPS provider fails with NSAE is because of the following two conditions: 1) it overrides Provider.putService(...) method, so that the logic for saving the registered SecureRandom services is NEVER used and thus the Provider class is not aware of this registration. 2) the service is found through legacy registration which is constructed inside the Provider class when parsing legacy entries and does not match what BCFIPS provider stores internally Thus, when trying to instantiate this default Provider.Service object, it fails the checks and throw NSAE as a result.
02-07-2020